feat: adding the skin_shader_generator, and gacha base barebone

This commit is contained in:
2026-04-24 00:17:00 +08:00
parent 16c82a48b8
commit 7e4b707e84
196 changed files with 4883 additions and 200 deletions
@@ -14,7 +14,7 @@
[ext_resource type="Texture2D" uid="uid://dpkx1a780pvwv" path="res://assets/textures/tile_diamond.png" id="10_sx8rm"] [ext_resource type="Texture2D" uid="uid://dpkx1a780pvwv" path="res://assets/textures/tile_diamond.png" id="10_sx8rm"]
[ext_resource type="BoxMesh" uid="uid://fy4bhoeii40c" path="res://addons/enhanced_gridmap/meshlibrary/tile_safe_zone.tres" id="10_uwjsj"] [ext_resource type="BoxMesh" uid="uid://fy4bhoeii40c" path="res://addons/enhanced_gridmap/meshlibrary/tile_safe_zone.tres" id="10_uwjsj"]
[ext_resource type="BoxMesh" uid="uid://b5cc3prem52r6" path="res://addons/enhanced_gridmap/meshlibrary/tile_freeze.tres" id="11_pgnbl"] [ext_resource type="BoxMesh" uid="uid://b5cc3prem52r6" path="res://addons/enhanced_gridmap/meshlibrary/tile_freeze.tres" id="11_pgnbl"]
[ext_resource type="BoxMesh" uid="uid://dcjdwbffgtutt" path="res://addons/enhanced_gridmap/meshlibrary/tile_non_walkable.tres" id="11_uwjsj"] [ext_resource type="BoxMesh" path="res://addons/enhanced_gridmap/meshlibrary/tile_non_walkable.tres" id="11_uwjsj"]
[ext_resource type="Texture2D" uid="uid://cdnxwlysxnujd" path="res://assets/textures/tile_heart.png" id="12_heart_tex"] [ext_resource type="Texture2D" uid="uid://cdnxwlysxnujd" path="res://assets/textures/tile_heart.png" id="12_heart_tex"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_uxput"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_uxput"]
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://4l05lp5erjs2"]
[ext_resource type="Texture2D" uid="uid://brsifb7crs32y" path="res://assets/characters/skins/clothing/oldpop_gloves_blue.png" id="1_f3hoj"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_f3hoj")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://ghpalciewcxf"]
[ext_resource type="Texture2D" uid="uid://p1ihslqnrxjq" path="res://assets/characters/skins/clothing/oldpop_body_greypants.png" id="1_o4mmw"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_o4mmw")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://pw4r007grvwt"]
[ext_resource type="Texture2D" uid="uid://d0wp6uqk30u6c" path="res://assets/characters/skins/clothing/oldpop_hat_blue.png" id="1_r5h0f"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_r5h0f")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://dws5gca78lnr"]
[ext_resource type="Texture2D" uid="uid://d4ifn6pltc7bc" path="res://assets/characters/skins/clothing/oldpop_hat_green.png" id="1_1e1rw"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_1e1rw")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://by4g43m5ye1c6"]
[ext_resource type="Texture2D" uid="uid://df8atdr3fyhsc" path="res://assets/characters/skins/clothing/oldpop_hat_red.png" id="1_bwoi0"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_bwoi0")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://bwhs3jw8vhvlp"]
[ext_resource type="Texture2D" uid="uid://b2a16sgrudj5q" path="res://assets/characters/skins/clothing/oldpop_body_originalpants.png" id="1_vfhdr"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_vfhdr")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://cotb4jiu7tebe"]
[ext_resource type="Texture2D" uid="uid://d4naeyq8i6h7s" path="res://assets/characters/skins/clothing/oldpop_gloves_red.png" id="1_x4qqh"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_x4qqh")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://g8olk8cxjbmt"]
[ext_resource type="Texture2D" uid="uid://b3wychpmdlheb" path="res://assets/characters/skins/clothing/oldpop_body_redpants.png" id="1_ko8ty"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_ko8ty")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://bpq6irfh1kof1"]
[ext_resource type="Texture2D" uid="uid://cimvaxvrbnob5" path="res://assets/characters/skins/clothing/oldpop_gloves_yellow.png" id="1_u1y8q"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_u1y8q")
@@ -1,9 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://bvwyinggho1f4"]
[ext_resource type="Texture2D" uid="uid://biiy6hk1l75ek" path="res://assets/characters/skins/clothing/oldpop_body_yellowpants.png" id="1_0pbr2"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_0pbr2")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://w40b5h01rdsh"]
[ext_resource type="Texture2D" uid="uid://doadhfi1wkpu8" path="res://assets/characters/skins/tex/bob_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_cloth_grey_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_cloth_red_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_cloth_yellow_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_cloth_grey_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_cloth_red_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_cloth_yellow_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_cloth_grey_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_cloth_red_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,6 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://be0jy2nkhhquy"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://csfwnrjb5a2v4"
path="res://.godot/imported/oldpop_cloth_white.png-1c0d4075c414911b05de4cc77cfe74e0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/clothing/oldpop_cloth_white.png"
dest_files=["res://.godot/imported/oldpop_cloth_white.png-1c0d4075c414911b05de4cc77cfe74e0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d0egs6j3sg0me"
path.s3tc="res://.godot/imported/oldpop_cloth_white_pant.png-a367f6f4f091bba7e63c3dcc90b20b36.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_cloth_white_pant.png-a367f6f4f091bba7e63c3dcc90b20b36.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/clothing/oldpop_cloth_white_pant.png"
dest_files=["res://.godot/imported/oldpop_cloth_white_pant.png-a367f6f4f091bba7e63c3dcc90b20b36.s3tc.ctex", "res://.godot/imported/oldpop_cloth_white_pant.png-a367f6f4f091bba7e63c3dcc90b20b36.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://p1ihslqnrxjq" path="res://assets/characters/skins/tex/oldpop_cloth_grey_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://b2a16sgrudj5q" path="res://assets/characters/skins/tex/oldpop_cloth_ori_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://b3wychpmdlheb" path="res://assets/characters/skins/tex/oldpop_cloth_red_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://v1qdug4x2ifm"]
[ext_resource type="Texture2D" uid="uid://d0egs6j3sg0me" path="res://assets/characters/skins/clothing/oldpop_cloth_white_pant.png" id="1_fw7uu"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1_fw7uu")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://biiy6hk1l75ek" path="res://assets/characters/skins/tex/oldpop_cloth_yellow_pant.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_gloves_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_gloves_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_gloves_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_gloves_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_gloves_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_gloves_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_gloves_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_gloves_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_gloves_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_gloves_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_gloves_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_gloves_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://brsifb7crs32y" path="res://assets/characters/skins/tex/oldpop_gloves_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://b0bhc0755oqgm" path="res://assets/characters/skins/tex/oldpop_gloves_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://d4naeyq8i6h7s" path="res://assets/characters/skins/tex/oldpop_gloves_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://cimvaxvrbnob5" path="res://assets/characters/skins/tex/oldpop_gloves_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_hat_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_hat_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_hat_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/bob_hat_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_hat_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_hat_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_hat_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/gatot_hat_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_hat_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_hat_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_hat_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" path="res://assets/characters/skins/tex/masbro_hat_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -2,16 +2,16 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://685lyodh7wrw" uid="uid://cx2antvcswa6p"
path="res://.godot/imported/oldpop_hat_yellow.png-f812e67c257915c9d8b9fe22724d0759.ctex" path="res://.godot/imported/oldpop_hat_white.png-2076758fa03ae3b17d5f92b877dc936f.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_hat_yellow.png" source_file="res://assets/characters/skins/hat/oldpop_hat_white.png"
dest_files=["res://.godot/imported/oldpop_hat_yellow.png-f812e67c257915c9d8b9fe22724d0759.ctex"] dest_files=["res://.godot/imported/oldpop_hat_white.png-2076758fa03ae3b17d5f92b877dc936f.ctex"]
[params] [params]
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://d0wp6uqk30u6c" path="res://assets/characters/skins/tex/oldpop_hat_blue.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://d4ifn6pltc7bc" path="res://assets/characters/skins/tex/oldpop_hat_green.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://df8atdr3fyhsc" path="res://assets/characters/skins/tex/oldpop_hat_red.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
[gd_resource type="StandardMaterial3D" format=3]
[ext_resource type="Texture2D" uid="uid://685lyodh7wrw" path="res://assets/characters/skins/tex/oldpop_hat_yellow.png" id="1"]
[resource]
transparency = 2
alpha_scissor_threshold = 0.5
alpha_antialiasing_mode = 0
albedo_texture = ExtResource("1")
@@ -0,0 +1,22 @@
{
"bob-body": {
"category": 2,
"fill_color": "ffffffff",
"img_path": "",
"img_pos": [
0.5,
0.5
],
"img_rot": 0.0,
"img_scale": 1.0,
"mask": [
"(0.0, 0.0)",
"(0.0, 0.0)",
"(0.0, 0.0)",
"(0.0, 0.0)",
"(0.0, 0.0)",
"(0.0, 0.0)"
],
"ref_path": ""
}
}
@@ -0,0 +1,39 @@
{
"oldpop-body": {
"category": 2,
"fill_color": "ffffffff",
"img_path": "",
"img_pos": [
0.5,
0.5
],
"img_rot": 0.0,
"img_scale": 1.0,
"masks": [
[
"(0.016667, 0.663542)",
"(0.147917, 0.665625)",
"(0.266667, 0.621875)",
"(0.370833, 0.615625)",
"(0.439583, 0.590625)",
"(0.441667, 0.948958)",
"(0.014583, 0.948958)",
"(0.016667, 0.665625)"
]
],
"ref_path": ""
},
"oldpop-bottom1": {
"category": -1,
"fill_color": "ffffffff",
"img_path": "",
"img_pos": [
0.5,
0.0
],
"img_rot": 0.0,
"img_scale": 1.0,
"masks": [],
"ref_path": ""
}
}

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cb3fdeskrctep"
path="res://.godot/imported/bob_cloth_grey_pant.png-fa010f7183e78f14eb9656d3651932ac.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_cloth_grey_pant.png"
dest_files=["res://.godot/imported/bob_cloth_grey_pant.png-fa010f7183e78f14eb9656d3651932ac.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -2,9 +2,9 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://d0wp6uqk30u6c" uid="uid://doadhfi1wkpu8"
path.s3tc="res://.godot/imported/oldpop_hat_blue.png-916a3ef8ca17067c6aafbe431ee36cdb.s3tc.ctex" path.s3tc="res://.godot/imported/bob_cloth_ori_pant.png-5ff5249a44da9d1cd2d7f3a9b732fab4.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_hat_blue.png-916a3ef8ca17067c6aafbe431ee36cdb.etc2.ctex" path.etc2="res://.godot/imported/bob_cloth_ori_pant.png-5ff5249a44da9d1cd2d7f3a9b732fab4.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_hat_blue.png" source_file="res://assets/characters/skins/tex/bob_cloth_ori_pant.png"
dest_files=["res://.godot/imported/oldpop_hat_blue.png-916a3ef8ca17067c6aafbe431ee36cdb.s3tc.ctex", "res://.godot/imported/oldpop_hat_blue.png-916a3ef8ca17067c6aafbe431ee36cdb.etc2.ctex"] dest_files=["res://.godot/imported/bob_cloth_ori_pant.png-5ff5249a44da9d1cd2d7f3a9b732fab4.s3tc.ctex", "res://.godot/imported/bob_cloth_ori_pant.png-5ff5249a44da9d1cd2d7f3a9b732fab4.etc2.ctex"]
[params] [params]

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cp1sj2fax8s23"
path="res://.godot/imported/bob_cloth_red_pant.png-40b77712cac1150279e39edc40f68ce9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_cloth_red_pant.png"
dest_files=["res://.godot/imported/bob_cloth_red_pant.png-40b77712cac1150279e39edc40f68ce9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cm53ribjw530m"
path="res://.godot/imported/bob_cloth_yellow_pant.png-4386f3df6b3148db3f2f5270a87dbf57.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_cloth_yellow_pant.png"
dest_files=["res://.godot/imported/bob_cloth_yellow_pant.png-4386f3df6b3148db3f2f5270a87dbf57.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cbqlf5kihfpum"
path.s3tc="res://.godot/imported/bob_gloves_blue.png-264b3df402a43b4878cb9452c63d3dcc.s3tc.ctex"
path.etc2="res://.godot/imported/bob_gloves_blue.png-264b3df402a43b4878cb9452c63d3dcc.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/bob_gloves_blue.png"
dest_files=["res://.godot/imported/bob_gloves_blue.png-264b3df402a43b4878cb9452c63d3dcc.s3tc.ctex", "res://.godot/imported/bob_gloves_blue.png-264b3df402a43b4878cb9452c63d3dcc.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://clp3vlo7b8iux"
path.s3tc="res://.godot/imported/bob_gloves_green.png-038f24ac834ef7652d881337f7931e92.s3tc.ctex"
path.etc2="res://.godot/imported/bob_gloves_green.png-038f24ac834ef7652d881337f7931e92.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/bob_gloves_green.png"
dest_files=["res://.godot/imported/bob_gloves_green.png-038f24ac834ef7652d881337f7931e92.s3tc.ctex", "res://.godot/imported/bob_gloves_green.png-038f24ac834ef7652d881337f7931e92.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dbq13bblr7mca"
path.s3tc="res://.godot/imported/bob_gloves_red.png-bc7d9689012d5d2ead549ab966a54c67.s3tc.ctex"
path.etc2="res://.godot/imported/bob_gloves_red.png-bc7d9689012d5d2ead549ab966a54c67.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/bob_gloves_red.png"
dest_files=["res://.godot/imported/bob_gloves_red.png-bc7d9689012d5d2ead549ab966a54c67.s3tc.ctex", "res://.godot/imported/bob_gloves_red.png-bc7d9689012d5d2ead549ab966a54c67.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://blrrrtw3uv8kw"
path="res://.godot/imported/bob_gloves_yellow.png-33a8bc0847e2211358e3b41594779f08.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_gloves_yellow.png"
dest_files=["res://.godot/imported/bob_gloves_yellow.png-33a8bc0847e2211358e3b41594779f08.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://du418q1jknsw8"
path.s3tc="res://.godot/imported/bob_hat_blue.png-57417e8a69bed9f67343cecdf032a75f.s3tc.ctex"
path.etc2="res://.godot/imported/bob_hat_blue.png-57417e8a69bed9f67343cecdf032a75f.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/bob_hat_blue.png"
dest_files=["res://.godot/imported/bob_hat_blue.png-57417e8a69bed9f67343cecdf032a75f.s3tc.ctex", "res://.godot/imported/bob_hat_blue.png-57417e8a69bed9f67343cecdf032a75f.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://1dpsw3qjl71m"
path.s3tc="res://.godot/imported/bob_hat_green.png-1971c6591fa2399d0fba65f5b34f3e0a.s3tc.ctex"
path.etc2="res://.godot/imported/bob_hat_green.png-1971c6591fa2399d0fba65f5b34f3e0a.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/bob_hat_green.png"
dest_files=["res://.godot/imported/bob_hat_green.png-1971c6591fa2399d0fba65f5b34f3e0a.s3tc.ctex", "res://.godot/imported/bob_hat_green.png-1971c6591fa2399d0fba65f5b34f3e0a.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c65wl2er1u413"
path="res://.godot/imported/bob_hat_red.png-245e3521d71544859cf527fb750fc029.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_hat_red.png"
dest_files=["res://.godot/imported/bob_hat_red.png-245e3521d71544859cf527fb750fc029.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cy7jsxj16trfn"
path="res://.godot/imported/bob_hat_yellow.png-d82efee98e652003550c16c8e67fadd5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/bob_hat_yellow.png"
dest_files=["res://.godot/imported/bob_hat_yellow.png-d82efee98e652003550c16c8e67fadd5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dcjptiyl5b7bj"
path="res://.godot/imported/gatot_cloth_grey_pant.png-41f98c153b53c31ae587b2ea6ea454dc.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_cloth_grey_pant.png"
dest_files=["res://.godot/imported/gatot_cloth_grey_pant.png-41f98c153b53c31ae587b2ea6ea454dc.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cwkw537aatuot"
path.s3tc="res://.godot/imported/gatot_cloth_ori_pant.png-4de8b806a642731e435e188b4e5cf8b4.s3tc.ctex"
path.etc2="res://.godot/imported/gatot_cloth_ori_pant.png-4de8b806a642731e435e188b4e5cf8b4.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_cloth_ori_pant.png"
dest_files=["res://.godot/imported/gatot_cloth_ori_pant.png-4de8b806a642731e435e188b4e5cf8b4.s3tc.ctex", "res://.godot/imported/gatot_cloth_ori_pant.png-4de8b806a642731e435e188b4e5cf8b4.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bftqhgrf5s05u"
path="res://.godot/imported/gatot_cloth_red_pant.png-39ab8676dc3d8d8aec6016ae6b7139b0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_cloth_red_pant.png"
dest_files=["res://.godot/imported/gatot_cloth_red_pant.png-39ab8676dc3d8d8aec6016ae6b7139b0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c4cyf66d2dwgt"
path="res://.godot/imported/gatot_cloth_yellow_pant.png-79371cbbe0ed3f9f40d438e439d547bf.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_cloth_yellow_pant.png"
dest_files=["res://.godot/imported/gatot_cloth_yellow_pant.png-79371cbbe0ed3f9f40d438e439d547bf.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cgcmw8rkl83lq"
path.s3tc="res://.godot/imported/gatot_gloves_blue.png-032092b83fa792b60e77a71361a497f4.s3tc.ctex"
path.etc2="res://.godot/imported/gatot_gloves_blue.png-032092b83fa792b60e77a71361a497f4.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_gloves_blue.png"
dest_files=["res://.godot/imported/gatot_gloves_blue.png-032092b83fa792b60e77a71361a497f4.s3tc.ctex", "res://.godot/imported/gatot_gloves_blue.png-032092b83fa792b60e77a71361a497f4.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cju2mhtumxp6h"
path="res://.godot/imported/gatot_gloves_green.png-353d568fc736c87799f2c272fdda8262.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_gloves_green.png"
dest_files=["res://.godot/imported/gatot_gloves_green.png-353d568fc736c87799f2c272fdda8262.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://hxd7b344ct8h"
path="res://.godot/imported/gatot_gloves_red.png-dce7c17404f6d5c0340d4309331b18a1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_gloves_red.png"
dest_files=["res://.godot/imported/gatot_gloves_red.png-dce7c17404f6d5c0340d4309331b18a1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cyx1tafb7ynju"
path="res://.godot/imported/gatot_gloves_yellow.png-1f071168f37d5286a650a9a9c297077a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_gloves_yellow.png"
dest_files=["res://.godot/imported/gatot_gloves_yellow.png-1f071168f37d5286a650a9a9c297077a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dvdmyjoupu854"
path="res://.godot/imported/gatot_hat_blue.png-b907a96952b46d1ccc710e941b5c8cf4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_hat_blue.png"
dest_files=["res://.godot/imported/gatot_hat_blue.png-b907a96952b46d1ccc710e941b5c8cf4.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b57ybp6hxfaii"
path="res://.godot/imported/gatot_hat_green.png-3307329708a7bfd671001d0c1ff187f0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_hat_green.png"
dest_files=["res://.godot/imported/gatot_hat_green.png-3307329708a7bfd671001d0c1ff187f0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://duxbwwr3bwrly"
path="res://.godot/imported/gatot_hat_red.png-a1d58ef9c2d5cec80a913916405123a7.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_hat_red.png"
dest_files=["res://.godot/imported/gatot_hat_red.png-a1d58ef9c2d5cec80a913916405123a7.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://btlx0dwaob1xi"
path="res://.godot/imported/gatot_hat_yellow.png-624dfd6eae34b457896b846fa02aaa1e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/gatot_hat_yellow.png"
dest_files=["res://.godot/imported/gatot_hat_yellow.png-624dfd6eae34b457896b846fa02aaa1e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bmwnhr6xere3t"
path="res://.godot/imported/masbro_cloth_grey_pant.png-8de527c7c27127db6b227a12290216be.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_cloth_grey_pant.png"
dest_files=["res://.godot/imported/masbro_cloth_grey_pant.png-8de527c7c27127db6b227a12290216be.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://s5erj2bmnkg"
path="res://.godot/imported/masbro_cloth_ori_pant.png-003723a0e220f5b63371c14edf2dfd54.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_cloth_ori_pant.png"
dest_files=["res://.godot/imported/masbro_cloth_ori_pant.png-003723a0e220f5b63371c14edf2dfd54.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bht217bpl1xhm"
path.s3tc="res://.godot/imported/masbro_cloth_red_pant.png-0255803c4f2376d7cbcf148abd571b6d.s3tc.ctex"
path.etc2="res://.godot/imported/masbro_cloth_red_pant.png-0255803c4f2376d7cbcf148abd571b6d.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_cloth_red_pant.png"
dest_files=["res://.godot/imported/masbro_cloth_red_pant.png-0255803c4f2376d7cbcf148abd571b6d.s3tc.ctex", "res://.godot/imported/masbro_cloth_red_pant.png-0255803c4f2376d7cbcf148abd571b6d.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b8r1c85q322c3"
path.s3tc="res://.godot/imported/masbro_cloth_yellow_pant.png-033c8e1aebfb051a0e6b1310fc5c98bd.s3tc.ctex"
path.etc2="res://.godot/imported/masbro_cloth_yellow_pant.png-033c8e1aebfb051a0e6b1310fc5c98bd.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_cloth_yellow_pant.png"
dest_files=["res://.godot/imported/masbro_cloth_yellow_pant.png-033c8e1aebfb051a0e6b1310fc5c98bd.s3tc.ctex", "res://.godot/imported/masbro_cloth_yellow_pant.png-033c8e1aebfb051a0e6b1310fc5c98bd.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d4m8e15wne0u"
path="res://.godot/imported/masbro_gloves_blue.png-73a428e11462c2e1b917f4e8554145c1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_gloves_blue.png"
dest_files=["res://.godot/imported/masbro_gloves_blue.png-73a428e11462c2e1b917f4e8554145c1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b37t7jtthrrtw"
path="res://.godot/imported/masbro_gloves_green.png-3fa68d578af809cbf03326ef73867611.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_gloves_green.png"
dest_files=["res://.godot/imported/masbro_gloves_green.png-3fa68d578af809cbf03326ef73867611.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cgwu20ifkhfyi"
path="res://.godot/imported/masbro_gloves_red.png-2ec0d5bb0f3ff6d7067d7a03bc3511a2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_gloves_red.png"
dest_files=["res://.godot/imported/masbro_gloves_red.png-2ec0d5bb0f3ff6d7067d7a03bc3511a2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://clrbtu0qn0owf"
path="res://.godot/imported/masbro_gloves_yellow.png-5e6a744a93855952d24f2de9d729cbe2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_gloves_yellow.png"
dest_files=["res://.godot/imported/masbro_gloves_yellow.png-5e6a744a93855952d24f2de9d729cbe2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bovejv3j6h3xm"
path="res://.godot/imported/masbro_hat_blue.png-62d6988fab47484b17f5e74d9129fa33.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_hat_blue.png"
dest_files=["res://.godot/imported/masbro_hat_blue.png-62d6988fab47484b17f5e74d9129fa33.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c2u7bgs1asnw2"
path="res://.godot/imported/masbro_hat_green.png-f633bd1fdca5a9eb978890890f370ce9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_hat_green.png"
dest_files=["res://.godot/imported/masbro_hat_green.png-f633bd1fdca5a9eb978890890f370ce9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bvxy8741y1rkw"
path="res://.godot/imported/masbro_hat_red.png-cd4210cf1ecc3216bfa7e2ed5bd3227a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_hat_red.png"
dest_files=["res://.godot/imported/masbro_hat_red.png-cd4210cf1ecc3216bfa7e2ed5bd3227a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://u8280glj8iyd"
path="res://.godot/imported/masbro_hat_yellow.png-0e88a6048fd9ed11a8e3887dd016737d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/masbro_hat_yellow.png"
dest_files=["res://.godot/imported/masbro_hat_yellow.png-0e88a6048fd9ed11a8e3887dd016737d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://p1ihslqnrxjq" uid="uid://p1ihslqnrxjq"
path.s3tc="res://.godot/imported/oldpop_body_greypants.png-6ad64e5720f512b94685c7cf02d5741c.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_cloth_grey_pant.png-d84a599db62cc45990318529f32890cc.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_body_greypants.png-6ad64e5720f512b94685c7cf02d5741c.etc2.ctex" path.etc2="res://.godot/imported/oldpop_cloth_grey_pant.png-d84a599db62cc45990318529f32890cc.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_body_greypants.png" source_file="res://assets/characters/skins/tex/oldpop_cloth_grey_pant.png"
dest_files=["res://.godot/imported/oldpop_body_greypants.png-6ad64e5720f512b94685c7cf02d5741c.s3tc.ctex", "res://.godot/imported/oldpop_body_greypants.png-6ad64e5720f512b94685c7cf02d5741c.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_cloth_grey_pant.png-d84a599db62cc45990318529f32890cc.s3tc.ctex", "res://.godot/imported/oldpop_cloth_grey_pant.png-d84a599db62cc45990318529f32890cc.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://b2a16sgrudj5q" uid="uid://b2a16sgrudj5q"
path.s3tc="res://.godot/imported/oldpop_body_originalpants.png-525ea0a1ebb85e7724ba72a992ec08c8.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_cloth_ori_pant.png-56fe8941e649e37793230acb645ce5cd.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_body_originalpants.png-525ea0a1ebb85e7724ba72a992ec08c8.etc2.ctex" path.etc2="res://.godot/imported/oldpop_cloth_ori_pant.png-56fe8941e649e37793230acb645ce5cd.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_body_originalpants.png" source_file="res://assets/characters/skins/tex/oldpop_cloth_ori_pant.png"
dest_files=["res://.godot/imported/oldpop_body_originalpants.png-525ea0a1ebb85e7724ba72a992ec08c8.s3tc.ctex", "res://.godot/imported/oldpop_body_originalpants.png-525ea0a1ebb85e7724ba72a992ec08c8.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_cloth_ori_pant.png-56fe8941e649e37793230acb645ce5cd.s3tc.ctex", "res://.godot/imported/oldpop_cloth_ori_pant.png-56fe8941e649e37793230acb645ce5cd.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://b3wychpmdlheb" uid="uid://b3wychpmdlheb"
path.s3tc="res://.godot/imported/oldpop_body_redpants.png-24c7db3db51f38090f8d8a94ee62515b.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_cloth_red_pant.png-8c3611cad3e9e530f9e5807e121dc6b4.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_body_redpants.png-24c7db3db51f38090f8d8a94ee62515b.etc2.ctex" path.etc2="res://.godot/imported/oldpop_cloth_red_pant.png-8c3611cad3e9e530f9e5807e121dc6b4.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_body_redpants.png" source_file="res://assets/characters/skins/tex/oldpop_cloth_red_pant.png"
dest_files=["res://.godot/imported/oldpop_body_redpants.png-24c7db3db51f38090f8d8a94ee62515b.s3tc.ctex", "res://.godot/imported/oldpop_body_redpants.png-24c7db3db51f38090f8d8a94ee62515b.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_cloth_red_pant.png-8c3611cad3e9e530f9e5807e121dc6b4.s3tc.ctex", "res://.godot/imported/oldpop_cloth_red_pant.png-8c3611cad3e9e530f9e5807e121dc6b4.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dl3qh7uxljqse"
path="res://.godot/imported/oldpop_cloth_white.png-dddb60d47dcb664ce61a06b4cd98d06a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/characters/skins/tex/oldpop_cloth_white.png"
dest_files=["res://.godot/imported/oldpop_cloth_white.png-dddb60d47dcb664ce61a06b4cd98d06a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://biiy6hk1l75ek" uid="uid://biiy6hk1l75ek"
path.s3tc="res://.godot/imported/oldpop_body_yellowpants.png-c05c4454bb6f53b6d47600adb163d718.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_cloth_yellow_pant.png-0333cadede45243538538adf1f848ffb.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_body_yellowpants.png-c05c4454bb6f53b6d47600adb163d718.etc2.ctex" path.etc2="res://.godot/imported/oldpop_cloth_yellow_pant.png-0333cadede45243538538adf1f848ffb.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_body_yellowpants.png" source_file="res://assets/characters/skins/tex/oldpop_cloth_yellow_pant.png"
dest_files=["res://.godot/imported/oldpop_body_yellowpants.png-c05c4454bb6f53b6d47600adb163d718.s3tc.ctex", "res://.godot/imported/oldpop_body_yellowpants.png-c05c4454bb6f53b6d47600adb163d718.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_cloth_yellow_pant.png-0333cadede45243538538adf1f848ffb.s3tc.ctex", "res://.godot/imported/oldpop_cloth_yellow_pant.png-0333cadede45243538538adf1f848ffb.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://brsifb7crs32y" uid="uid://brsifb7crs32y"
path.s3tc="res://.godot/imported/oldpop_gloves_blue.png-55270fd48e68d1c1aafaab6ec78569e0.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_gloves_blue.png-07d033a86cea0ced42461a446ed56035.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_gloves_blue.png-55270fd48e68d1c1aafaab6ec78569e0.etc2.ctex" path.etc2="res://.godot/imported/oldpop_gloves_blue.png-07d033a86cea0ced42461a446ed56035.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_gloves_blue.png" source_file="res://assets/characters/skins/tex/oldpop_gloves_blue.png"
dest_files=["res://.godot/imported/oldpop_gloves_blue.png-55270fd48e68d1c1aafaab6ec78569e0.s3tc.ctex", "res://.godot/imported/oldpop_gloves_blue.png-55270fd48e68d1c1aafaab6ec78569e0.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_gloves_blue.png-07d033a86cea0ced42461a446ed56035.s3tc.ctex", "res://.godot/imported/oldpop_gloves_blue.png-07d033a86cea0ced42461a446ed56035.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://b0bhc0755oqgm" uid="uid://b0bhc0755oqgm"
path.s3tc="res://.godot/imported/oldpop_gloves_green.png-2d5dad982dfa21428d2b0363ea6b3408.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_gloves_green.png-80aebb9ac249151a3b77f0429ad3cabf.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_gloves_green.png-2d5dad982dfa21428d2b0363ea6b3408.etc2.ctex" path.etc2="res://.godot/imported/oldpop_gloves_green.png-80aebb9ac249151a3b77f0429ad3cabf.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_gloves_green.png" source_file="res://assets/characters/skins/tex/oldpop_gloves_green.png"
dest_files=["res://.godot/imported/oldpop_gloves_green.png-2d5dad982dfa21428d2b0363ea6b3408.s3tc.ctex", "res://.godot/imported/oldpop_gloves_green.png-2d5dad982dfa21428d2b0363ea6b3408.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_gloves_green.png-80aebb9ac249151a3b77f0429ad3cabf.s3tc.ctex", "res://.godot/imported/oldpop_gloves_green.png-80aebb9ac249151a3b77f0429ad3cabf.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://d4naeyq8i6h7s" uid="uid://d4naeyq8i6h7s"
path.s3tc="res://.godot/imported/oldpop_gloves_red.png-935695835e8f4567a5990a17cf33f758.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_gloves_red.png-996c63b128a5ca141c2dfdb773bb3b49.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_gloves_red.png-935695835e8f4567a5990a17cf33f758.etc2.ctex" path.etc2="res://.godot/imported/oldpop_gloves_red.png-996c63b128a5ca141c2dfdb773bb3b49.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_gloves_red.png" source_file="res://assets/characters/skins/tex/oldpop_gloves_red.png"
dest_files=["res://.godot/imported/oldpop_gloves_red.png-935695835e8f4567a5990a17cf33f758.s3tc.ctex", "res://.godot/imported/oldpop_gloves_red.png-935695835e8f4567a5990a17cf33f758.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_gloves_red.png-996c63b128a5ca141c2dfdb773bb3b49.s3tc.ctex", "res://.godot/imported/oldpop_gloves_red.png-996c63b128a5ca141c2dfdb773bb3b49.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://cimvaxvrbnob5" uid="uid://cimvaxvrbnob5"
path.s3tc="res://.godot/imported/oldpop_gloves_yellow.png-b349df58b3bc7ac80ac772778c5c881f.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_gloves_yellow.png-d8cfdbfd6d26d3d365b6904f5653be37.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_gloves_yellow.png-b349df58b3bc7ac80ac772778c5c881f.etc2.ctex" path.etc2="res://.godot/imported/oldpop_gloves_yellow.png-d8cfdbfd6d26d3d365b6904f5653be37.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_gloves_yellow.png" source_file="res://assets/characters/skins/tex/oldpop_gloves_yellow.png"
dest_files=["res://.godot/imported/oldpop_gloves_yellow.png-b349df58b3bc7ac80ac772778c5c881f.s3tc.ctex", "res://.godot/imported/oldpop_gloves_yellow.png-b349df58b3bc7ac80ac772778c5c881f.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_gloves_yellow.png-d8cfdbfd6d26d3d365b6904f5653be37.s3tc.ctex", "res://.godot/imported/oldpop_gloves_yellow.png-d8cfdbfd6d26d3d365b6904f5653be37.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d0wp6uqk30u6c"
path.s3tc="res://.godot/imported/oldpop_hat_blue.png-60ce1894b2725996a035127a88496de2.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_hat_blue.png-60ce1894b2725996a035127a88496de2.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/oldpop_hat_blue.png"
dest_files=["res://.godot/imported/oldpop_hat_blue.png-60ce1894b2725996a035127a88496de2.s3tc.ctex", "res://.godot/imported/oldpop_hat_blue.png-60ce1894b2725996a035127a88496de2.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://d4ifn6pltc7bc" uid="uid://d4ifn6pltc7bc"
path.s3tc="res://.godot/imported/oldpop_hat_green.png-5e928687ce3e8bfbc14df23b42992ca3.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_hat_green.png-8d363432371bcef32d0c00d213c09817.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_hat_green.png-5e928687ce3e8bfbc14df23b42992ca3.etc2.ctex" path.etc2="res://.godot/imported/oldpop_hat_green.png-8d363432371bcef32d0c00d213c09817.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_hat_green.png" source_file="res://assets/characters/skins/tex/oldpop_hat_green.png"
dest_files=["res://.godot/imported/oldpop_hat_green.png-5e928687ce3e8bfbc14df23b42992ca3.s3tc.ctex", "res://.godot/imported/oldpop_hat_green.png-5e928687ce3e8bfbc14df23b42992ca3.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_hat_green.png-8d363432371bcef32d0c00d213c09817.s3tc.ctex", "res://.godot/imported/oldpop_hat_green.png-8d363432371bcef32d0c00d213c09817.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -3,8 +3,8 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://df8atdr3fyhsc" uid="uid://df8atdr3fyhsc"
path.s3tc="res://.godot/imported/oldpop_hat_red.png-fcd79b63984a743f8a1f6646778473dc.s3tc.ctex" path.s3tc="res://.godot/imported/oldpop_hat_red.png-6696e607316bded7e33590a7ef488d5e.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_hat_red.png-fcd79b63984a743f8a1f6646778473dc.etc2.ctex" path.etc2="res://.godot/imported/oldpop_hat_red.png-6696e607316bded7e33590a7ef488d5e.etc2.ctex"
metadata={ metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"], "imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true "vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps] [deps]
source_file="res://assets/characters/skins/clothing/oldpop_hat_red.png" source_file="res://assets/characters/skins/tex/oldpop_hat_red.png"
dest_files=["res://.godot/imported/oldpop_hat_red.png-fcd79b63984a743f8a1f6646778473dc.s3tc.ctex", "res://.godot/imported/oldpop_hat_red.png-fcd79b63984a743f8a1f6646778473dc.etc2.ctex"] dest_files=["res://.godot/imported/oldpop_hat_red.png-6696e607316bded7e33590a7ef488d5e.s3tc.ctex", "res://.godot/imported/oldpop_hat_red.png-6696e607316bded7e33590a7ef488d5e.etc2.ctex"]
[params] [params]
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://685lyodh7wrw"
path.s3tc="res://.godot/imported/oldpop_hat_yellow.png-45886db87082c0e9019227a9cf383df3.s3tc.ctex"
path.etc2="res://.godot/imported/oldpop_hat_yellow.png-45886db87082c0e9019227a9cf383df3.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/characters/skins/tex/oldpop_hat_yellow.png"
dest_files=["res://.godot/imported/oldpop_hat_yellow.png-45886db87082c0e9019227a9cf383df3.s3tc.ctex", "res://.godot/imported/oldpop_hat_yellow.png-45886db87082c0e9019227a9cf383df3.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
+82
View File
@@ -0,0 +1,82 @@
{
"banners": {
"star": {
"name": "Star Banner",
"currency": "star",
"pull_1_cost": 160,
"pull_10_cost": 1440,
"pity_at": 90,
"rates": {
"common": 0.60,
"uncommon": 0.25,
"rare": 0.14,
"real_prize": 0.01
}
},
"gold": {
"name": "Gold Banner",
"currency": "gold",
"pull_1_cost": 50,
"pull_10_cost": 450,
"pity_at": 90,
"rates": {
"common": 0.60,
"uncommon": 0.25,
"rare": 0.14,
"real_prize": 0.01
}
}
},
"fragments": {
"frag_common": { "name": "Common Fragment", "rarity": "common", "icon": "⬜" },
"frag_uncommon": { "name": "Uncommon Fragment", "rarity": "uncommon", "icon": "🟩" },
"frag_rare": { "name": "Rare Fragment", "rarity": "rare", "icon": "🟦" }
},
"pools": {
"common": ["frag_common"],
"uncommon": ["frag_uncommon"],
"rare": ["frag_rare"],
"real_prize": [
"skin_gacha_rainbow_suit",
"skin_gacha_dragon_hat",
"skin_gacha_phantom_gloves",
"skin_gacha_neon_acc"
]
},
"real_prize_catalog": {
"skin_gacha_rainbow_suit": { "name": "Rainbow Suit", "category": "costume", "rarity": "real_prize", "character": "" },
"skin_gacha_dragon_hat": { "name": "Dragon Hat", "category": "head", "rarity": "real_prize", "character": "" },
"skin_gacha_phantom_gloves": { "name": "Phantom Gloves", "category": "glove", "rarity": "real_prize", "character": "" },
"skin_gacha_neon_acc": { "name": "Neon Accessory", "category": "accessory","rarity": "real_prize", "character": "" }
},
"craft_recipes": {
"craft_skin_oldpop_golden": {
"name": "Oldpop Golden Suit",
"category": "costume",
"character": "Oldpop",
"result_id": "oldpop_golden_suit",
"cost": { "frag_common": 30, "frag_uncommon": 15, "frag_rare": 5 }
},
"craft_skin_masbro_fire": {
"name": "Masbro Fire Set",
"category": "costume",
"character": "Masbro",
"result_id": "masbro_fire_set",
"cost": { "frag_common": 25, "frag_uncommon": 12, "frag_rare": 3 }
},
"craft_skin_bob_cyber": {
"name": "Bob Cyber Hat",
"category": "head",
"character": "Bob",
"result_id": "bob_cyber_hat",
"cost": { "frag_common": 20, "frag_uncommon": 8, "frag_rare": 2 }
},
"craft_skin_gatot_storm": {
"name": "Gatot Storm Gloves",
"category": "glove",
"character": "Gatot",
"result_id": "gatot_storm_gloves",
"cost": { "frag_common": 15, "frag_uncommon": 6, "frag_rare": 1 }
}
}
}
+157 -35
View File
@@ -3,13 +3,61 @@
{ {
"category": "head", "category": "head",
"character": "Oldpop", "character": "Oldpop",
"gold": 0, "gold": 100,
"item_id": "example-hat", "item_id": "oldpop-blue-hat",
"name": "Example Hat", "name": "Oldpop Blue Hat",
"rarity": "Common", "rarity": "Common",
"slots": [ "slots": [
{ {
"material": "", "material": "res://assets/characters/skins/hat/oldpop_mat_hat_blue.tres",
"mesh": "oldpop-hat1",
"mode": "override"
}
],
"star": 0
},
{
"category": "head",
"character": "Oldpop",
"gold": 100,
"item_id": "oldpop-green-hat",
"name": "Oldpop Green Hat",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/hat/oldpop_mat_hat_green.tres",
"mesh": "oldpop-hat1",
"mode": "override"
}
],
"star": 0
},
{
"category": "head",
"character": "Oldpop",
"gold": 100,
"item_id": "oldpop-red-hat",
"name": "Oldpop Red Hat",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/hat/oldpop_mat_hat_red.tres",
"mesh": "oldpop-hat1",
"mode": "override"
}
],
"star": 0
},
{
"category": "head",
"character": "Oldpop",
"gold": 100,
"item_id": "oldpop-yellow-hat",
"name": "Oldpop Yellow Hat",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/hat/oldpop_mat_hat_yellow.tres",
"mesh": "oldpop-hat1", "mesh": "oldpop-hat1",
"mode": "override" "mode": "override"
} }
@@ -19,23 +67,23 @@
{ {
"category": "costume", "category": "costume",
"character": "Oldpop", "character": "Oldpop",
"gold": 200, "gold": 0,
"item_id": "oldpop-grey-pant", "item_id": "oldpop-og-pant",
"name": "Copper Grey Pant", "name": "Copper OG Pant",
"rarity": "Common", "rarity": "Common",
"slots": [ "slots": [
{ {
"material": "res://assets/characters/skins/clothing/bmo_greypants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres",
"mesh": "oldpop-body", "mesh": "oldpop-body",
"mode": "overlay" "mode": "overlay"
}, },
{ {
"material": "res://assets/characters/skins/clothing/bmo_greypants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres",
"mesh": "oldpop-bottom1", "mesh": "oldpop-bottom1",
"mode": "override" "mode": "override"
}, },
{ {
"material": "res://assets/characters/skins/clothing/bmo_greypants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres",
"mesh": "oldpop-bottom2", "mesh": "oldpop-bottom2",
"mode": "override" "mode": "override"
} }
@@ -45,23 +93,75 @@
{ {
"category": "costume", "category": "costume",
"character": "Oldpop", "character": "Oldpop",
"gold": 0, "gold": 150,
"item_id": "oldpop-clothing-original", "item_id": "oldpop-grey-pant",
"name": "Copper Original Pants", "name": "Copper Grey Pant",
"rarity": "Common", "rarity": "Common",
"slots": [ "slots": [
{ {
"material": "res://assets/characters/skins/clothing/bmo_originalpants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres",
"mesh": "oldpop-body", "mesh": "oldpop-body",
"mode": "overlay" "mode": "overlay"
}, },
{ {
"material": "res://assets/characters/skins/clothing/bmo_originalpants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres",
"mesh": "oldpop-bottom1", "mesh": "oldpop-bottom1",
"mode": "override" "mode": "override"
}, },
{ {
"material": "res://assets/characters/skins/clothing/bmo_originalpants.tres", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres",
"mesh": "oldpop-bottom2",
"mode": "override"
}
],
"star": 0
},
{
"category": "costume",
"character": "Oldpop",
"gold": 150,
"item_id": "oldpop-red-pant",
"name": "Copper Red Pant",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres",
"mesh": "oldpop-body",
"mode": "overlay"
},
{
"material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres",
"mesh": "oldpop-bottom1",
"mode": "override"
},
{
"material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres",
"mesh": "oldpop-bottom2",
"mode": "override"
}
],
"star": 0
},
{
"category": "costume",
"character": "Oldpop",
"gold": 150,
"item_id": "oldpop-yellow-pant",
"name": "Copper Yellow Pant",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres",
"mesh": "oldpop-body",
"mode": "overlay"
},
{
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres",
"mesh": "oldpop-bottom1",
"mode": "override"
},
{
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres",
"mesh": "oldpop-bottom2", "mesh": "oldpop-bottom2",
"mode": "override" "mode": "override"
} }
@@ -71,13 +171,13 @@
{ {
"category": "glove", "category": "glove",
"character": "Oldpop", "character": "Oldpop",
"gold": 150, "gold": 75,
"item_id": "example-gloves", "item_id": "oldpop-blue-gloves",
"name": "Example Gloves", "name": "Oldpop Blue Gloves",
"rarity": "Common", "rarity": "Common",
"slots": [ "slots": [
{ {
"material": "", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_blue.tres",
"mesh": "oldpop-hands", "mesh": "oldpop-hands",
"mode": "override" "mode": "override"
} }
@@ -85,26 +185,48 @@
"star": 0 "star": 0
}, },
{ {
"category": "costume", "category": "glove",
"character": "Oldpop", "character": "Oldpop",
"gold": 200, "gold": 75,
"item_id": "oldpop-red-pant", "item_id": "oldpop-green-gloves",
"name": "Copper Red Pant", "name": "Oldpop Green Gloves",
"rarity": "Rare", "rarity": "Common",
"slots": [ "slots": [
{ {
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_green.tres",
"mesh": "oldpop-body", "mesh": "oldpop-hands",
"mode": "overlay"
},
{
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres",
"mesh": "oldpop-bottom1",
"mode": "override" "mode": "override"
}, }
],
"star": 0
},
{
"category": "glove",
"character": "Oldpop",
"gold": 75,
"item_id": "oldpop-red-gloves",
"name": "Oldpop Red Gloves",
"rarity": "Common",
"slots": [
{ {
"material": "res://assets/characters/skins/clothing/bmo_redpants.tres", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_red.tres",
"mesh": "oldpop-bottom2", "mesh": "oldpop-hands",
"mode": "override"
}
],
"star": 0
},
{
"category": "glove",
"character": "Oldpop",
"gold": 75,
"item_id": "oldpop-yellow-gloves",
"name": "Oldpop Yellow Gloves",
"rarity": "Common",
"slots": [
{
"material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_yellow.tres",
"mesh": "oldpop-hands",
"mode": "override" "mode": "override"
} }
], ],
+2 -1
View File
@@ -22,6 +22,7 @@ config/icon="res://icon.svg"
[autoload] [autoload]
GameUpdateManager="*res://scripts/managers/game_update_manager.gd"
Nakama="*uid://bueyqhhvxe0tx" Nakama="*uid://bueyqhhvxe0tx"
NakamaManager="*res://scripts/nakama_manager.gd" NakamaManager="*res://scripts/nakama_manager.gd"
AuthManager="*res://scripts/managers/auth_manager.gd" AuthManager="*res://scripts/managers/auth_manager.gd"
@@ -39,7 +40,7 @@ NameGenerator="*res://scripts/generators/name_generator.gd"
MusicManager="*res://scripts/managers/music_manager.gd" MusicManager="*res://scripts/managers/music_manager.gd"
AdminManager="*res://scripts/managers/admin_manager.gd" AdminManager="*res://scripts/managers/admin_manager.gd"
SkinManager="*res://scripts/managers/skin_manager.gd" SkinManager="*res://scripts/managers/skin_manager.gd"
GameUpdateManager="*res://scripts/managers/game_update_manager.gd" GachaManager="*res://scripts/managers/gacha_manager.gd"
[display] [display]
+2
View File
@@ -7,4 +7,6 @@ layout_mode = 3
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_editor") script = ExtResource("1_editor")
+520
View File
@@ -0,0 +1,520 @@
[gd_scene format=3 uid="uid://bfn70q6drs4oy"]
[ext_resource type="Script" uid="uid://dbcyurv4m7mka" path="res://scripts/tools/skin_shader_generator.gd" id="1_script"]
[ext_resource type="Texture2D" uid="uid://c1i00chwkmxtw" path="res://assets/characters/Oldpop_oldpop-tex.png" id="2_ac8h2"]
[node name="SkinShaderGenerator" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_script")
[node name="MainHSplit" type="HSplitContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 6.0
offset_top = 6.0
offset_right = -6.0
offset_bottom = -6.0
grow_horizontal = 2
grow_vertical = 2
split_offsets = PackedInt32Array(480)
split_offset = 480
[node name="UVEditorVBox" type="VBoxContainer" parent="MainHSplit"]
custom_minimum_size = Vector2(480, 0)
layout_mode = 2
[node name="UVPanel" type="PanelContainer" parent="MainHSplit/UVEditorVBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="UVPreview" type="TextureRect" parent="MainHSplit/UVEditorVBox/UVPanel"]
unique_name_in_owner = true
layout_mode = 2
texture = ExtResource("2_ac8h2")
expand_mode = 1
stretch_mode = 5
[node name="UVOverlay" type="Control" parent="MainHSplit/UVEditorVBox/UVPanel"]
unique_name_in_owner = true
layout_mode = 2
[node name="UVToolsHBox" type="HBoxContainer" parent="MainHSplit/UVEditorVBox"]
custom_minimum_size = Vector2(0, 28)
layout_mode = 2
[node name="ShowAllUVs" type="CheckBox" parent="MainHSplit/UVEditorVBox/UVToolsHBox"]
unique_name_in_owner = true
layout_mode = 2
text = "Show All UVs"
[node name="FlipUV" type="CheckBox" parent="MainHSplit/UVEditorVBox/UVToolsHBox"]
unique_name_in_owner = true
layout_mode = 2
text = "Flip UV"
[node name="HideRef" type="CheckBox" parent="MainHSplit/UVEditorVBox/UVToolsHBox"]
unique_name_in_owner = true
layout_mode = 2
text = "Hide Ref"
[node name="RightHSplit" type="HSplitContainer" parent="MainHSplit"]
layout_mode = 2
split_offsets = PackedInt32Array(400)
split_offset = 400
[node name="PreviewVBox" type="VBoxContainer" parent="MainHSplit/RightHSplit"]
layout_mode = 2
[node name="ViewportPanel" type="PanelContainer" parent="MainHSplit/RightHSplit/PreviewVBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="ViewportContainer" type="SubViewportContainer" parent="MainHSplit/RightHSplit/PreviewVBox/ViewportPanel"]
layout_mode = 2
stretch = true
[node name="Viewport3D" type="SubViewport" parent="MainHSplit/RightHSplit/PreviewVBox/ViewportPanel/ViewportContainer"]
unique_name_in_owner = true
own_world_3d = true
handle_input_locally = false
msaa_3d = 2
size = Vector2i(400, 646)
render_target_update_mode = 4
[node name="ZoomHBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/PreviewVBox"]
layout_mode = 2
[node name="ZoomMinus" type="Button" parent="MainHSplit/RightHSplit/PreviewVBox/ZoomHBox"]
unique_name_in_owner = true
layout_mode = 2
text = " "
[node name="ZoomSlider" type="HSlider" parent="MainHSplit/RightHSplit/PreviewVBox/ZoomHBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
min_value = 0.3
max_value = 10.0
step = 0.1
value = 1.8
[node name="ZoomPlus" type="Button" parent="MainHSplit/RightHSplit/PreviewVBox/ZoomHBox"]
unique_name_in_owner = true
layout_mode = 2
text = " + "
[node name="InspectedLabel" type="Label" parent="MainHSplit/RightHSplit/PreviewVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 0, 1)
horizontal_alignment = 1
[node name="TabContainer" type="TabContainer" parent="MainHSplit/RightHSplit"]
unique_name_in_owner = true
custom_minimum_size = Vector2(360, 0)
layout_mode = 2
current_tab = 1
[node name="Scene Tree" type="ScrollContainer" parent="MainHSplit/RightHSplit/TabContainer"]
visible = false
layout_mode = 2
metadata/_tab_index = 0
[node name="MeshList" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Scene Tree"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
[node name="Inspector" type="ScrollContainer" parent="MainHSplit/RightHSplit/TabContainer"]
layout_mode = 2
horizontal_scroll_mode = 0
metadata/_tab_index = 1
[node name="PIPanel" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 12
[node name="Margin" type="MarginContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel"]
layout_mode = 2
theme_override_constants/margin_left = 6
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 6
theme_override_constants/margin_bottom = 6
[node name="VBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0, 1, 1, 1)
text = "▼ Part Properties"
[node name="PIName" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 0, 1)
text = "(no part selected)"
[node name="Grid" type="GridContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
layout_mode = 2
columns = 2
[node name="Label4" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
text = "Ref UV Img:"
[node name="PIRefHBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
[node name="PIRefBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid/PIRefHBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Default"
text_overrun_behavior = 3
[node name="PIRefClear" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid/PIRefHBox"]
unique_name_in_owner = true
layout_mode = 2
text = "✕"
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
text = "Category:"
[node name="PICategory" type="OptionButton" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
[node name="Label2" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
text = "Fill Color:"
[node name="PIColor" type="ColorPickerButton" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
unique_name_in_owner = true
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
color = Color(1, 1, 1, 1)
[node name="Label3" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
text = "Sticker Img:"
[node name="PIImageHBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid"]
layout_mode = 2
[node name="PIImageBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid/PIImageHBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "None"
text_overrun_behavior = 3
[node name="PIImageClear" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/Grid/PIImageHBox"]
unique_name_in_owner = true
layout_mode = 2
text = "✕"
[node name="TransformVBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_constants/separation = 8
[node name="HBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox"]
layout_mode = 2
text = "Pos X:"
[node name="PIPosX" type="HSlider" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
min_value = -1.0
max_value = 2.0
step = 0.01
[node name="HBox2" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox2"]
layout_mode = 2
text = "Pos Y:"
[node name="PIPosY" type="HSlider" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox2"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
min_value = -1.0
max_value = 2.0
step = 0.01
[node name="HBox3" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox3"]
layout_mode = 2
text = "Scale:"
[node name="PIScale" type="HSlider" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox3"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
min_value = 0.01
max_value = 5.0
step = 0.01
value = 1.0
[node name="HBox4" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox4"]
layout_mode = 2
text = "Rotate:"
[node name="PIRot" type="HSlider" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/TransformVBox/HBox4"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
min_value = -180.0
max_value = 180.0
[node name="HSeparator" type="HSeparator" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
layout_mode = 2
[node name="MaskSection" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="HBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection"]
layout_mode = 2
[node name="Label2" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection/HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_colors/font_color = Color(1, 1, 0, 1)
text = "UV Masks (isolate regions):"
[node name="AddMaskBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection/HBox"]
unique_name_in_owner = true
layout_mode = 2
text = "+ Add"
[node name="MaskList" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection"]
unique_name_in_owner = true
layout_mode = 2
[node name="DrawingToolbar" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection"]
unique_name_in_owner = true
visible = false
layout_mode = 2
[node name="DrawStatus" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection/DrawingToolbar"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Editing Mask A..."
[node name="FinishBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection/DrawingToolbar"]
unique_name_in_owner = true
layout_mode = 2
text = "✓ Done"
[node name="ClearBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Inspector/PIPanel/Margin/VBox/MaskSection/DrawingToolbar"]
unique_name_in_owner = true
layout_mode = 2
text = "✕ Clear"
[node name="Settings" type="ScrollContainer" parent="MainHSplit/RightHSplit/TabContainer"]
visible = false
layout_mode = 2
horizontal_scroll_mode = 0
metadata/_tab_index = 2
[node name="VBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 10
[node name="Margin" type="MarginContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox"]
layout_mode = 2
theme_override_constants/margin_left = 6
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 6
theme_override_constants/margin_bottom = 6
[node name="VBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="CharBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/CharBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.5, 1, 1, 1)
text = "Active Character:"
[node name="CharacterOpt" type="OptionButton" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/CharBox"]
unique_name_in_owner = true
layout_mode = 2
[node name="WireBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/WireBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.5, 1, 1, 1)
text = "Wireframe Opacity:"
[node name="WireOpacity" type="HSlider" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/WireBox"]
unique_name_in_owner = true
layout_mode = 2
max_value = 1.0
step = 0.05
value = 0.07
[node name="HBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/WireBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/WireBox/HBox"]
layout_mode = 2
text = "Color:"
[node name="WireColor" type="OptionButton" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/WireBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
selected = 0
[node name="HSeparator" type="HSeparator" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox"]
layout_mode = 2
[node name="PresetBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/PresetBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.5, 1, 1, 1)
text = "Session Presets:"
[node name="HBox" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/PresetBox"]
layout_mode = 2
[node name="SavePresetBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/PresetBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "💾 Save JSON"
[node name="LoadPresetBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox/PresetBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "📂 Load JSON"
[node name="Label2" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Settings/VBox/Margin/VBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.5, 0.5, 0.5, 1)
theme_override_font_sizes/font_size = 12
text = "Workflow:
1. Click mesh in Scene Tree.
2. Set Category & Color in Inspector.
3. Add Sticker/Decal if needed.
4. Hit GENERATE to bake."
autowrap_mode = 3
[node name="Export" type="ScrollContainer" parent="MainHSplit/RightHSplit/TabContainer"]
visible = false
layout_mode = 2
horizontal_scroll_mode = 0
metadata/_tab_index = 3
[node name="ExportVBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Export"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Margin" type="MarginContainer" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox"]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="VBox" type="VBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0, 1, 0.5, 1)
text = "▼ Export Assets"
[node name="PrefixLabel" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0, 1, 0.5, 1)
theme_override_font_sizes/font_size = 13
text = "oldpop_skin_"
horizontal_alignment = 2
[node name="HBoxContainer" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer"]
layout_mode = 2
text = "Name:"
[node name="ExportName" type="LineEdit" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "custom_name"
[node name="HBoxContainer2" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer2"]
layout_mode = 2
text = "Target Folder:"
[node name="ExportFolder" type="OptionButton" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
[node name="HBoxContainer3" type="HBoxContainer" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
layout_mode = 2
[node name="Label" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer3"]
layout_mode = 2
text = "Mode:"
[node name="ExportMode" type="OptionButton" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox/HBoxContainer3"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
[node name="GenerateBtn" type="Button" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 44)
layout_mode = 2
text = "🚀 GENERATE & EXPORT"
[node name="StatusLabel" type="Label" parent="MainHSplit/RightHSplit/TabContainer/Export/ExportVBox/Margin/VBox"]
unique_name_in_owner = true
layout_mode = 2
horizontal_alignment = 1
+95
View File
@@ -0,0 +1,95 @@
[gd_scene format=3 uid="uid://frag_craft_panel_001"]
[ext_resource type="Script" path="res://scripts/ui/fragment_craft_panel.gd" id="1"]
[ext_resource type="Theme" uid="uid://da337sh5qxi0s" path="res://assets/themes/ui_theme.tres" id="2"]
[ext_resource type="FontFile" uid="uid://xnjx058n4tsw" path="res://assets/fonts/Nougat-ExtraBlack.ttf" id="3_font"]
[node name="FragmentCraftPanel" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2")
script = ExtResource("1")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.04, 0.04, 0.08, 0.96)
[node name="MainMargin" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 20
[node name="MainVBox" type="VBoxContainer" parent="MainMargin"]
layout_mode = 2
theme_override_constants/separation = 14
[node name="TopBar" type="HBoxContainer" parent="MainMargin/MainVBox"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="BackBtn" type="Button" parent="MainMargin/MainVBox/TopBar"]
unique_name_in_owner = true
custom_minimum_size = Vector2(44, 44)
layout_mode = 2
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 22
text = "←"
[node name="TitleLabel" type="Label" parent="MainMargin/MainVBox/TopBar"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_colors/font_color = Color(0.4, 1.0, 0.7, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 24
text = "🧩 Fragment Craft"
[node name="FragBalance" type="Label" parent="MainMargin/MainVBox/TopBar"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.85, 0.85, 0.85, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 14
text = "⬜ ×0 🟩 ×0 🟦 ×0"
[node name="SubTitle" type="Label" parent="MainMargin/MainVBox"]
layout_mode = 2
theme_override_colors/font_color = Color(0.65, 0.65, 0.65, 1)
theme_override_font_sizes/font_size = 13
text = "Collect Common, Uncommon, and Rare fragments from gacha pulls to craft exclusive skins."
[node name="HSep" type="HSeparator" parent="MainMargin/MainVBox"]
layout_mode = 2
[node name="ScrollContainer" type="ScrollContainer" parent="MainMargin/MainVBox"]
layout_mode = 2
size_flags_vertical = 3
horizontal_scroll_mode = 0
[node name="RecipeList" type="VBoxContainer" parent="MainMargin/MainVBox/ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 10
[node name="StatusLabel" type="Label" parent="MainMargin/MainVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 14
horizontal_alignment = 1
text = ""
+267
View File
@@ -0,0 +1,267 @@
[gd_scene format=3 uid="uid://gacha_panel_001"]
[ext_resource type="Script" path="res://scripts/ui/gacha_panel.gd" id="1"]
[ext_resource type="Theme" uid="uid://da337sh5qxi0s" path="res://assets/themes/ui_theme.tres" id="2"]
[ext_resource type="FontFile" uid="uid://xnjx058n4tsw" path="res://assets/fonts/Nougat-ExtraBlack.ttf" id="3_font"]
[node name="GachaPanel" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2")
script = ExtResource("1")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.04, 0.04, 0.08, 0.95)
[node name="MainMargin" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 28
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 28
theme_override_constants/margin_bottom = 20
[node name="MainVBox" type="VBoxContainer" parent="MainMargin"]
layout_mode = 2
theme_override_constants/separation = 14
[node name="TopBar" type="HBoxContainer" parent="MainMargin/MainVBox"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="BackBtn" type="Button" parent="MainMargin/MainVBox/TopBar"]
unique_name_in_owner = true
custom_minimum_size = Vector2(44, 44)
layout_mode = 2
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 22
text = "←"
[node name="TitleLabel" type="Label" parent="MainMargin/MainVBox/TopBar"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_colors/font_color = Color(1.0, 0.85, 0.25, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 26
text = "✨ Gacha"
[node name="CraftBtn" type="Button" parent="MainMargin/MainVBox/TopBar"]
unique_name_in_owner = true
custom_minimum_size = Vector2(130, 40)
layout_mode = 2
theme_override_colors/font_color = Color(0.4, 1.0, 0.7, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 14
text = "🧩 Fragment Craft"
[node name="BannerTabs" type="HBoxContainer" parent="MainMargin/MainVBox"]
layout_mode = 2
theme_override_constants/separation = 12
alignment = 1
[node name="StarTabBtn" type="Button" parent="MainMargin/MainVBox/BannerTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(160, 48)
layout_mode = 2
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 18
text = "✦ Star Banner"
[node name="GoldTabBtn" type="Button" parent="MainMargin/MainVBox/BannerTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(160, 48)
layout_mode = 2
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 18
text = "▤ Gold Banner"
[node name="ContentHBox" type="HBoxContainer" parent="MainMargin/MainVBox"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/separation = 20
[node name="LeftPanel" type="PanelContainer" parent="MainMargin/MainVBox/ContentHBox"]
custom_minimum_size = Vector2(320, 0)
layout_mode = 2
[node name="LeftMargin" type="MarginContainer" parent="MainMargin/MainVBox/ContentHBox/LeftPanel"]
layout_mode = 2
theme_override_constants/margin_left = 18
theme_override_constants/margin_top = 18
theme_override_constants/margin_right = 18
theme_override_constants/margin_bottom = 18
[node name="LeftVBox" type="VBoxContainer" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin"]
layout_mode = 2
theme_override_constants/separation = 14
[node name="BannerLabel" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(1.0, 0.85, 0.25, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 22
text = "Star Banner"
horizontal_alignment = 1
[node name="BalanceRow" type="HBoxContainer" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
layout_mode = 2
theme_override_constants/separation = 8
alignment = 1
[node name="BalanceLbl" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/BalanceRow"]
layout_mode = 2
theme_override_colors/font_color = Color(0.7, 0.7, 0.7)
theme_override_font_sizes/font_size = 13
text = "Balance:"
[node name="BalanceLabel" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/BalanceRow"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.9, 0.75, 0.2, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 18
text = "✦ 0"
[node name="PityLabel" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.6, 0.6, 0.9, 1)
theme_override_font_sizes/font_size = 13
text = "Pity: 0 / 90"
horizontal_alignment = 1
[node name="HSep1" type="HSeparator" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
layout_mode = 2
[node name="Pull1Row" type="HBoxContainer" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="Pull1Btn" type="Button" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/Pull1Row"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 44)
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 16
text = "1× Pull"
[node name="Cost1Label" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/Pull1Row"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.9, 0.75, 0.2, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 14
text = "✦ 160"
[node name="Pull10Row" type="HBoxContainer" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="Pull10Btn" type="Button" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/Pull10Row"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 44)
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 16
text = "10× Pull"
[node name="Cost10Label" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox/Pull10Row"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.9, 0.75, 0.2, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 14
text = "✦ 1440"
[node name="StatusLabel" type="Label" parent="MainMargin/MainVBox/ContentHBox/LeftPanel/LeftMargin/LeftVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_colors/font_color = Color(0.9, 0.4, 0.4, 1)
theme_override_font_sizes/font_size = 13
horizontal_alignment = 1
text = ""
[node name="RightPanel" type="PanelContainer" parent="MainMargin/MainVBox/ContentHBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="RightMargin" type="MarginContainer" parent="MainMargin/MainVBox/ContentHBox/RightPanel"]
layout_mode = 2
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 16
theme_override_constants/margin_bottom = 16
[node name="RatesLabel" type="RichTextLabel" parent="MainMargin/MainVBox/ContentHBox/RightPanel/RightMargin"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_font_sizes/font_size = 13
text = ""
fit_content = true
[node name="ResultPanel" type="PanelContainer" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -450.0
offset_top = -260.0
offset_right = 450.0
offset_bottom = 260.0
grow_horizontal = 2
grow_vertical = 2
[node name="ResultVBox" type="VBoxContainer" parent="ResultPanel"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="ResultTitle" type="Label" parent="ResultPanel/ResultVBox"]
layout_mode = 2
theme_override_colors/font_color = Color(1, 0.9, 0.3, 1)
theme_override_fonts/font = ExtResource("3_font")
theme_override_font_sizes/font_size = 20
text = "Pull Results"
horizontal_alignment = 1
[node name="ScrollContainer" type="ScrollContainer" parent="ResultPanel/ResultVBox"]
layout_mode = 2
size_flags_vertical = 3
custom_minimum_size = Vector2(0, 160)
[node name="ResultGrid" type="GridContainer" parent="ResultPanel/ResultVBox/ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/h_separation = 8
theme_override_constants/v_separation = 8
columns = 5
[node name="CloseResultBtn" type="Button" parent="ResultPanel/ResultVBox"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 38)
layout_mode = 2
theme_override_fonts/font = ExtResource("3_font")
text = "Close"
+7
View File
@@ -316,6 +316,13 @@ layout_mode = 2
theme_override_font_sizes/font_size = 28 theme_override_font_sizes/font_size = 28
text = "💎" text = "💎"
[node name="FragTabBtn" type="Button" parent="MainMargin/MainHBox/CenterCol/CategoryTabs" unique_id=1985872465]
unique_name_in_owner = true
custom_minimum_size = Vector2(56, 56)
layout_mode = 2
theme_override_font_sizes/font_size = 28
text = "🧩"
[node name="ViewportWrapper" type="Control" parent="MainMargin/MainHBox/CenterCol" unique_id=1095002692] [node name="ViewportWrapper" type="Control" parent="MainMargin/MainHBox/CenterCol" unique_id=1095002692]
layout_mode = 2 layout_mode = 2
size_flags_vertical = 3 size_flags_vertical = 3
+45
View File
@@ -0,0 +1,45 @@
@tool
extends SceneTree
func _init():
var models = {
"Oldpop": "res://assets/characters/Oldpop.glb",
"Bob": "res://assets/characters/Bob.glb",
"Gatot": "res://assets/characters/Gatot.glb",
"Masbro": "res://assets/characters/Masbro.glb"
}
for name in models:
print("\n=== Inspecting %s ===" % name)
var scene = load(models[name]).instantiate()
_inspect_node(scene)
quit()
func _inspect_node(node: Node):
if node is MeshInstance3D:
_print_mesh_uv_bounds(node)
for child in node.get_children():
_inspect_node(child)
func _print_mesh_uv_bounds(mi: MeshInstance3D):
var mesh = mi.mesh
if not mesh: return
var min_uv = Vector2(1e10, 1e10)
var max_uv = Vector2(-1e10, -1e10)
for s in mesh.get_surface_count():
var arrays = mesh.surface_get_arrays(s)
var uvs = arrays[Mesh.ARRAY_TEX_UV]
if not uvs: continue
for uv in uvs:
min_uv.x = min(min_uv.x, uv.x)
min_uv.y = min(min_uv.y, uv.y)
max_uv.x = max(max_uv.x, uv.x)
max_uv.y = max(max_uv.y, uv.y)
print("- Mesh: %s" % mi.name)
print(" UV Min: %s" % min_uv)
print(" UV Max: %s" % max_uv)
+1
View File
@@ -0,0 +1 @@
uid://bb0wohmy3qlnh
+137
View File
@@ -0,0 +1,137 @@
extends Node
## GachaManager — Autoload singleton
## Handles pull logic, pity counter, and fragment reward dispatch.
const DATA_PATH = "res://assets/data/gacha_data.json"
var data: Dictionary = {}
# pity_counters[banner_id] = int
var pity_counters: Dictionary = {"star": 0, "gold": 0}
signal pull_completed(results: Array) # Array of {id, rarity, name}
func _ready() -> void:
_load_data()
func _load_data() -> void:
var f := FileAccess.open(DATA_PATH, FileAccess.READ)
if f:
var parsed = JSON.parse_string(f.get_as_text())
if parsed is Dictionary:
data = parsed
else:
push_error("[GachaManager] Could not open gacha_data.json")
# ─── Public API ──────────────────────────────────────────────────────────────
func pull(banner_id: String, count: int) -> Array:
if data.is_empty(): _load_data()
var banner: Dictionary = data.get("banners", {}).get(banner_id, {})
if banner.is_empty():
push_error("[GachaManager] Unknown banner: " + banner_id)
return []
var currency: String = banner.get("currency", "star")
var cost_key: String = "pull_%d_cost" % count
var cost: int = banner.get(cost_key, banner.get("pull_1_cost", 999) * count)
var pity_at: int = banner.get("pity_at", 90)
# Deduct currency
var bal: int = UserProfileManager.wallet.get(currency, 0)
if bal < cost:
push_warning("[GachaManager] Not enough %s (have %d need %d)" % [currency, bal, cost])
return []
UserProfileManager.wallet[currency] = bal - cost
UserProfileManager.save_wallet()
var results: Array = []
for _i in range(count):
var pity: int = pity_counters.get(banner_id, 0)
var rarity: String
if pity + 1 >= pity_at:
rarity = "real_prize"
pity_counters[banner_id] = 0
else:
rarity = _roll_rarity(banner.get("rates", {}))
pity_counters[banner_id] = (pity + 1) if rarity != "real_prize" else 0
var item_id: String = _pick_from_pool(rarity, banner_id)
var item_data: Dictionary = _resolve_item(item_id, rarity)
results.append({
"id": item_id,
"rarity": rarity,
"name": item_data.get("name", item_id)
})
_grant_item(item_id, rarity)
pull_completed.emit(results)
return results
func get_pity(banner_id: String) -> int:
return pity_counters.get(banner_id, 0)
func get_balance(banner_id: String) -> int:
var banner: Dictionary = data.get("banners", {}).get(banner_id, {})
var currency: String = banner.get("currency", "star")
return UserProfileManager.wallet.get(currency, 0)
# ─── Internal ─────────────────────────────────────────────────────────────────
func _roll_rarity(rates: Dictionary) -> String:
var roll := randf()
var cumulative := 0.0
for rarity in ["real_prize", "rare", "uncommon", "common"]:
cumulative += rates.get(rarity, 0.0)
if roll <= cumulative:
return rarity
return "common"
func _pick_from_pool(rarity: String, _banner_id: String) -> String:
var pool: Array = data.get("pools", {}).get(rarity, [])
if pool.is_empty(): return ""
return pool[randi() % pool.size()]
func _resolve_item(item_id: String, rarity: String) -> Dictionary:
if rarity == "real_prize":
return data.get("real_prize_catalog", {}).get(item_id, {})
return data.get("fragments", {}).get(item_id, {})
func _grant_item(item_id: String, rarity: String) -> void:
if rarity == "real_prize":
# Add skin directly to inventory
if not UserProfileManager.inventory.has(item_id):
UserProfileManager.inventory.append(item_id)
else:
# Add fragment count
var frags: Dictionary = UserProfileManager.fragments
frags[item_id] = frags.get(item_id, 0) + 1
UserProfileManager.fragments = frags
# ─── Crafting ─────────────────────────────────────────────────────────────────
func get_all_recipes() -> Dictionary:
return data.get("craft_recipes", {})
func can_craft(recipe_id: String) -> bool:
var recipe: Dictionary = data.get("craft_recipes", {}).get(recipe_id, {})
if recipe.is_empty(): return false
var cost: Dictionary = recipe.get("cost", {})
for frag_id in cost:
var needed: int = cost[frag_id]
var have: int = UserProfileManager.fragments.get(frag_id, 0)
if have < needed: return false
return true
func craft(recipe_id: String) -> bool:
if not can_craft(recipe_id): return false
var recipe: Dictionary = data.get("craft_recipes", {}).get(recipe_id, {})
var cost: Dictionary = recipe.get("cost", {})
for frag_id in cost:
UserProfileManager.fragments[frag_id] -= cost[frag_id]
var result_id: String = recipe.get("result_id", "")
if not result_id.is_empty():
if not UserProfileManager.inventory.has(result_id):
UserProfileManager.inventory.append(result_id)
UserProfileManager.save_wallet()
return true
+1
View File
@@ -0,0 +1 @@
uid://m5g6vki8s87y
+67 -16
View File
@@ -23,34 +23,64 @@ extends Node
const SKIN_CATALOG: Dictionary = { const SKIN_CATALOG: Dictionary = {
# ── [HEAD] ────────────────────────────────────────────────────────────────────── # ── [HEAD] ──────────────────────────────────────────────────────────────────────
"example-hat": { "oldpop-blue-hat": {
"category": "head", "category": "head",
"character": "Oldpop", "character": "Oldpop",
"slots": [ "slots": [
{ "mesh": "oldpop-hat1", "mode": "override", "material": "" }, { "mesh": "oldpop-hat1", "mode": "override", "material": "res://assets/characters/skins/hat/oldpop_mat_hat_blue.tres" },
]
},
"oldpop-green-hat": {
"category": "head",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hat1", "mode": "override", "material": "res://assets/characters/skins/hat/oldpop_mat_hat_green.tres" },
]
},
"oldpop-red-hat": {
"category": "head",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hat1", "mode": "override", "material": "res://assets/characters/skins/hat/oldpop_mat_hat_red.tres" },
]
},
"oldpop-yellow-hat": {
"category": "head",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hat1", "mode": "override", "material": "res://assets/characters/skins/hat/oldpop_mat_hat_yellow.tres" },
] ]
}, },
# ── [COSTUME] ────────────────────────────────────────────────────────────────────── # ── [COSTUME] ──────────────────────────────────────────────────────────────────────
"oldpop-og-pant": {
"category": "costume",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres" },
{ "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres" },
{ "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_ori_pant.tres" },
]
},
"oldpop-grey-pant": { "oldpop-grey-pant": {
"category": "costume", "category": "costume",
"character": "Oldpop", "character": "Oldpop",
"slots": [ "slots": [
{ "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/bmo_greypants.tres" }, { "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
{ "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/bmo_greypants.tres" }, { "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
{ "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/bmo_greypants.tres" }, { "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
]
},
"oldpop-clothing-original": {
"category": "costume",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/bmo_originalpants.tres" },
{ "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/bmo_originalpants.tres" },
{ "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/bmo_originalpants.tres" },
] ]
}, },
"oldpop-red-pant": { "oldpop-red-pant": {
"category": "costume",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres" },
{ "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres" },
{ "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres" },
]
},
"oldpop-yellow-pant": {
"category": "costume", "category": "costume",
"character": "Oldpop", "character": "Oldpop",
"slots": [ "slots": [
@@ -61,11 +91,32 @@ const SKIN_CATALOG: Dictionary = {
}, },
# ── [GLOVE] ────────────────────────────────────────────────────────────────────── # ── [GLOVE] ──────────────────────────────────────────────────────────────────────
"example-gloves": { "oldpop-blue-gloves": {
"category": "glove", "category": "glove",
"character": "Oldpop", "character": "Oldpop",
"slots": [ "slots": [
{ "mesh": "oldpop-hands", "mode": "override", "material": "" }, { "mesh": "oldpop-hands", "mode": "override", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_blue.tres" },
]
},
"oldpop-green-gloves": {
"category": "glove",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hands", "mode": "override", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_green.tres" },
]
},
"oldpop-red-gloves": {
"category": "glove",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hands", "mode": "override", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_red.tres" },
]
},
"oldpop-yellow-gloves": {
"category": "glove",
"character": "Oldpop",
"slots": [
{ "mesh": "oldpop-hands", "mode": "override", "material": "res://assets/characters/skins/gloves/oldpop_mat_gloves_yellow.tres" },
] ]
}, },
+20
View File
@@ -20,6 +20,7 @@ signal avatar_changed(url: String)
var profile: Dictionary = {} var profile: Dictionary = {}
var stats: Dictionary = {} var stats: Dictionary = {}
var wallet: Dictionary = {"gold": 0, "star": 0} var wallet: Dictionary = {"gold": 0, "star": 0}
var fragments: Dictionary = {} # frag_common, frag_uncommon, frag_rare
var inventory: Array = [] var inventory: Array = []
var loadout: Dictionary = {"head": "", "costume": "", "glove": "", "accessory": ""} var loadout: Dictionary = {"head": "", "costume": "", "glove": "", "accessory": ""}
var shop_catalog: Dictionary = {} var shop_catalog: Dictionary = {}
@@ -51,6 +52,7 @@ func _on_auth_completed(success: bool, _user_data: Dictionary) -> void:
func _on_logged_out() -> void: func _on_logged_out() -> void:
profile = {} profile = {}
stats = {} stats = {}
fragments = {}
is_profile_loaded = false is_profile_loaded = false
# ============================================================================= # =============================================================================
@@ -62,6 +64,7 @@ func load_profile() -> Dictionary:
profile = {} profile = {}
stats = {} stats = {}
wallet = {"gold": 0, "star": 0} wallet = {"gold": 0, "star": 0}
fragments = {}
inventory = [] inventory = []
is_profile_loaded = false is_profile_loaded = false
@@ -116,6 +119,15 @@ func load_profile() -> Dictionary:
# Load stats # Load stats
await load_stats() await load_stats()
# Load fragments from storage
var frag_result = await NakamaManager.client.read_storage_objects_async(
NakamaManager.session,
[NakamaStorageObjectId.new(PROFILE_COLLECTION, "fragments", account.user.id)]
)
if not frag_result.is_exception() and frag_result.objects.size() > 0:
var fdata = JSON.parse_string(frag_result.objects[0].value)
if fdata is Dictionary: fragments = fdata
is_profile_loaded = true is_profile_loaded = true
emit_signal("profile_loaded", profile) emit_signal("profile_loaded", profile)
print("[UserProfileManager] Profile loaded: ", profile.get("display_name", "Unknown")) print("[UserProfileManager] Profile loaded: ", profile.get("display_name", "Unknown"))
@@ -391,6 +403,14 @@ func _reload_wallet() -> void:
wallet["star"] = w_data.get("star", 0) wallet["star"] = w_data.get("star", 0)
emit_signal("profile_updated") emit_signal("profile_updated")
func save_wallet() -> void:
"""Persist wallet deductions and fragment counts to Nakama storage."""
if not NakamaManager.session: return
var write_objs: Array = [
NakamaWriteStorageObject.new(PROFILE_COLLECTION, "fragments", 1, 1, JSON.stringify(fragments), "")
]
await NakamaManager.client.write_storage_objects_async(NakamaManager.session, write_objs)
# ============================================================================= # =============================================================================
# Stats Management # Stats Management
# ============================================================================= # =============================================================================
+81
View File
@@ -0,0 +1,81 @@
shader_type spatial;
render_mode depth_draw_always, cull_back;
uniform sampler2D albedo_texture : source_color;
uniform vec4 hat_color : source_color = vec4(1.0);
uniform vec4 gloves_color : source_color = vec4(1.0);
uniform vec4 cloth_color : source_color = vec4(1.0);
uniform vec4 skin_color : source_color = vec4(1.0);
uniform vec2 hat_uv_min = vec2(0.6, 0.1);
uniform vec2 hat_uv_max = vec2(1.0, 0.5);
uniform vec2 hat_uv_min2 = vec2(-1.0);
uniform vec2 hat_uv_max2 = vec2(-1.0);
uniform vec2 gloves_uv_min = vec2(0.6, 0.5);
uniform vec2 gloves_uv_max = vec2(1.0, 0.7);
uniform vec2 gloves_uv_min2 = vec2(-1.0);
uniform vec2 gloves_uv_max2 = vec2(-1.0);
uniform vec2 cloth_uv_min = vec2(0.0, 0.7);
uniform vec2 cloth_uv_max = vec2(1.0, 1.0);
uniform vec2 cloth_uv_min2 = vec2(-1.0);
uniform vec2 cloth_uv_max2 = vec2(-1.0);
uniform vec4 hat_match_color : source_color = vec4(0.0);
uniform vec4 gloves_match_color : source_color = vec4(0.0);
uniform vec4 cloth_match_color : source_color = vec4(0.0);
uniform float color_tolerance = 0.05;
uniform int highlight_part = -1; // -1: none, 0: hat, 1: gloves, 2: cloth, 3: skin
uniform float alpha_scissor_threshold : hint_range(0.0, 1.0) = 0.5;
uniform bool is_selected = false;
instance uniform int mesh_category : hint_range(-1, 3) = -1;
bool in_rect(vec2 uv, vec2 mi, vec2 ma) {
if (mi.x < 0.0) return false;
return uv.x >= mi.x && uv.x <= ma.x && uv.y >= mi.y && uv.y <= ma.y;
}
bool color_match(vec3 c1, vec3 c2) {
if (length(c2) < 0.01) return false; // Ignore black/empty targets
return distance(c1, c2) < color_tolerance;
}
void fragment() {
vec4 tex = texture(albedo_texture, UV);
if (tex.a < alpha_scissor_threshold) discard;
vec3 final_color = tex.rgb;
float emission_mult = 0.0;
if (is_selected) emission_mult = 0.4;
int cat = mesh_category;
// If no manual mesh assignment, use UV Detection + Color Match (Magic Wand)
if (cat == -1) {
if (in_rect(UV, hat_uv_min, hat_uv_max) || in_rect(UV, hat_uv_min2, hat_uv_max2) || color_match(tex.rgb, hat_match_color.rgb)) cat = 0;
else if (in_rect(UV, gloves_uv_min, gloves_uv_max) || in_rect(UV, gloves_uv_min2, gloves_uv_max2) || color_match(tex.rgb, gloves_match_color.rgb)) cat = 1;
else if (in_rect(UV, cloth_uv_min, cloth_uv_max) || in_rect(UV, cloth_uv_min2, cloth_uv_max2) || color_match(tex.rgb, cloth_match_color.rgb)) cat = 2;
else cat = 3;
}
if (cat == 0) {
final_color *= hat_color.rgb;
if (highlight_part == 0) emission_mult = 0.5;
} else if (cat == 1) {
final_color *= gloves_color.rgb;
if (highlight_part == 1) emission_mult = 0.5;
} else if (cat == 2) {
final_color *= cloth_color.rgb;
if (highlight_part == 2) emission_mult = 0.5;
} else {
final_color *= skin_color.rgb;
if (highlight_part == 3) emission_mult = 0.5;
}
ALBEDO = final_color;
EMISSION = final_color * emission_mult;
ALPHA = tex.a;
}
@@ -0,0 +1 @@
uid://pbq1c8la17vd
+58 -1
View File
@@ -40,6 +40,7 @@ var _form_star: SpinBox
var _form_category: OptionButton var _form_category: OptionButton
var _form_rarity: OptionButton var _form_rarity: OptionButton
var _slots_vbox: VBoxContainer var _slots_vbox: VBoxContainer
var _duplicate_btn: Button
var _delete_btn: Button var _delete_btn: Button
var _save_btn: Button var _save_btn: Button
@@ -77,6 +78,12 @@ func _build_ui() -> void:
add_btn.pressed.connect(_on_add_pressed) add_btn.pressed.connect(_on_add_pressed)
top.add_child(add_btn) top.add_child(add_btn)
_duplicate_btn = Button.new()
_duplicate_btn.text = "📋 Duplicate"
_duplicate_btn.disabled = true
_duplicate_btn.pressed.connect(_on_duplicate_pressed)
top.add_child(_duplicate_btn)
_delete_btn = Button.new() _delete_btn = Button.new()
_delete_btn.text = "✕ Delete" _delete_btn.text = "✕ Delete"
_delete_btn.disabled = true _delete_btn.disabled = true
@@ -247,7 +254,9 @@ func _refresh_list() -> void:
c.queue_free() c.queue_free()
for i in _data.size(): for i in _data.size():
var entry: Dictionary = _data[i] var entry: Dictionary = _data[i]
var btn := Button.new() var btn := SkinListItem.new()
btn.index = i
btn.editor = self
var cat: String = entry.get("category", "?") var cat: String = entry.get("category", "?")
var iid: String = entry.get("item_id", "?") var iid: String = entry.get("item_id", "?")
btn.text = "[%s]\n%s" % [cat, iid] btn.text = "[%s]\n%s" % [cat, iid]
@@ -273,11 +282,13 @@ func _populate_form() -> void:
if _selected_idx < 0 or _selected_idx >= _data.size(): if _selected_idx < 0 or _selected_idx >= _data.size():
_form_panel.visible = false _form_panel.visible = false
_no_sel_label.visible = true _no_sel_label.visible = true
_duplicate_btn.disabled = true
_delete_btn.disabled = true _delete_btn.disabled = true
return return
_form_panel.visible = true _form_panel.visible = true
_no_sel_label.visible = false _no_sel_label.visible = false
_duplicate_btn.disabled = false
_delete_btn.disabled = false _delete_btn.disabled = false
var e: Dictionary = _data[_selected_idx] var e: Dictionary = _data[_selected_idx]
@@ -388,6 +399,20 @@ func _on_add_pressed() -> void:
_set_status("New skin created. Fill in the form and Save & Generate.", Color.YELLOW) _set_status("New skin created. Fill in the form and Save & Generate.", Color.YELLOW)
func _on_duplicate_pressed() -> void:
if _selected_idx < 0:
return
_commit_form()
var original = _data[_selected_idx]
var duplicate = original.duplicate(true)
duplicate["item_id"] += "_copy"
_data.insert(_selected_idx + 1, duplicate)
_selected_idx += 1
_refresh_list()
_populate_form()
_set_status("Skin duplicated.", Color.YELLOW)
func _on_delete_pressed() -> void: func _on_delete_pressed() -> void:
if _selected_idx < 0: if _selected_idx < 0:
return return
@@ -399,6 +424,19 @@ func _on_delete_pressed() -> void:
_set_status("Deleted: " + removed, Color.YELLOW) _set_status("Deleted: " + removed, Color.YELLOW)
func move_item(from_idx: int, to_idx: int) -> void:
if from_idx == to_idx:
return
_commit_form()
var item = _data[from_idx]
_data.remove_at(from_idx)
_data.insert(to_idx, item)
_selected_idx = to_idx
_refresh_list()
_populate_form()
_set_status("Reordered: %s" % item.get("item_id", "?"), Color.WHITE)
func _on_add_slot_pressed() -> void: func _on_add_slot_pressed() -> void:
if _selected_idx < 0: if _selected_idx < 0:
return return
@@ -534,3 +572,22 @@ func _set_status(msg: String, color: Color = Color.WHITE) -> void:
return return
_status_label.add_theme_color_override("font_color", color) _status_label.add_theme_color_override("font_color", color)
_status_label.text = msg _status_label.text = msg
# ─── Inner Classes ───────────────────────────────────────────────────────────
class SkinListItem extends Button:
var index: int
var editor: Control
func _get_drag_data(_at_position: Vector2) -> Variant:
var preview := Button.new()
preview.text = text
preview.modulate.a = 0.5
set_drag_preview(preview)
return index
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
return typeof(data) == TYPE_INT
func _drop_data(_at_position: Vector2, data: Variant) -> void:
editor.move_item(data, index)
+724
View File
@@ -0,0 +1,724 @@
@tool
extends Control
const SHADER_PATH = "res://scripts/shaders/character_skin.gdshader"
const BASE_TEX_DIR = "res://assets/characters/skins/tex/"
const PRESET_DIR = "res://assets/characters/skins/presets/"
const EXPORT_DIRS = {
"Clothing": "res://assets/characters/skins/clothing/",
"Gloves": "res://assets/characters/skins/gloves/",
"Hat": "res://assets/characters/skins/hat/",
"General / Tex": "res://assets/characters/skins/tex/"
}
const CAT_NAMES = ["Hat", "Gloves", "Cloth", "Skin"]
# ─── UI Refs (Scene Unique Nodes) ───────────────────────────────────────────
@onready var _character_opt: OptionButton = %CharacterOpt
@onready var _status_label: Label = %StatusLabel
@onready var _inspected_label: Label = %InspectedLabel
@onready var _mesh_list_vbox: VBoxContainer = %MeshList
@onready var _zoom_slider: HSlider = %ZoomSlider
@onready var _uv_preview: TextureRect = %UVPreview
@onready var _uv_overlay: Control = %UVOverlay
@onready var _viewport_3d: SubViewport = %Viewport3D
@onready var _pi_name_lbl: Label = %PIName
@onready var _pi_cat_opt: OptionButton = %PICategory
@onready var _pi_color_btn: ColorPickerButton = %PIColor
@onready var _pi_image_btn: Button = %PIImageBtn
@onready var _pi_image_clear: Button = %PIImageClear
@onready var _pi_ref_btn: Button = %PIRefBtn
@onready var _pi_ref_clear: Button = %PIRefClear
@onready var _pi_pos_x: HSlider = %PIPosX
@onready var _pi_pos_y: HSlider = %PIPosY
@onready var _pi_scale: HSlider = %PIScale
@onready var _pi_rot: HSlider = %PIRot
@onready var _export_name: LineEdit = %ExportName
@onready var _export_mode: OptionButton = %ExportMode
@onready var _export_folder_opt: OptionButton = %ExportFolder
@onready var _prefix_label: Label = %PrefixLabel
@onready var _wire_opacity_slider: HSlider = %WireOpacity
@onready var _wire_color_opt: OptionButton = %WireColor
var _char_preview: Node3D
var _file_dialog: FileDialog
# ─── State ───────────────────────────────────────────────────────────────────
var _mesh_data: Array = []
var _inspected_mesh_name: String = ""
var _is_rotating: bool = false
var _last_mouse_pos: Vector2
var _show_all_uvs: bool = false
var _flip_uv: bool = false
var _hide_ref: bool = false
var _debug_wireframe: MeshInstance3D
var _drawing_mask: bool = false
var _current_mask_idx: int = -1
var _mask_points: PackedVector2Array = PackedVector2Array()
var _dragged_point_idx: int = -1
var _char_cache: Dictionary = {}
var _gizmo_state: int = 0 # 0: None, 1: Move, 2: Scale, 3: Rotate
var _gizmo_start_uv: Vector2
var _gizmo_start_val: Variant
func _ready() -> void:
for d in EXPORT_DIRS.values():
if not DirAccess.dir_exists_absolute(d): DirAccess.make_dir_recursive_absolute(d)
if not DirAccess.dir_exists_absolute(PRESET_DIR): DirAccess.make_dir_recursive_absolute(PRESET_DIR)
_setup_ui_connections()
call_deferred("_update_character_preview")
_update_export_prefix()
func _setup_ui_connections():
# Presets
%SavePresetBtn.pressed.connect(_on_save_preset)
%LoadPresetBtn.pressed.connect(_on_load_preset)
# Character selection
_character_opt.clear()
for c in ["Oldpop", "Masbro", "Bob", "Gatot"]: _character_opt.add_item(c)
_character_opt.selected = 0
_character_opt.item_selected.connect(func(i): _on_char_changed(i); _update_export_prefix())
# UV Viewport
_uv_overlay.draw.connect(_on_uv_overlay_draw)
_uv_overlay.gui_input.connect(_on_uv_input)
%ShowAllUVs.toggled.connect(func(v): _show_all_uvs = v; _uv_overlay.queue_redraw())
%FlipUV.toggled.connect(func(v): _flip_uv = v; _update_character_preview())
%HideRef.toggled.connect(func(v): _hide_ref = v; _uv_preview.visible = !v; _uv_overlay.queue_redraw())
# 3D Viewport
%Viewport3D.get_parent().gui_input.connect(_on_3d_input)
_setup_3d_scene()
# Zoom controls
%ZoomMinus.pressed.connect(func(): _zoom_slider.value += 0.4)
%ZoomPlus.pressed.connect(func(): _zoom_slider.value -= 0.4)
_zoom_slider.value_changed.connect(_on_zoom_changed)
# Part Inspector
_pi_cat_opt.clear(); _pi_cat_opt.add_item("None / Skin", -1)
for ci in range(3): _pi_cat_opt.add_item(CAT_NAMES[ci], ci)
_pi_cat_opt.item_selected.connect(_on_pi_cat_selected)
_pi_color_btn.color_changed.connect(_on_pi_color_changed)
_pi_image_btn.pressed.connect(func(): _on_pick_image("sticker"))
_pi_image_clear.pressed.connect(_on_clear_image)
_pi_ref_btn.pressed.connect(func(): _on_pick_image("ref"))
_pi_ref_clear.pressed.connect(_on_clear_ref)
for s in [_pi_pos_x, _pi_pos_y, _pi_scale, _pi_rot]:
s.value_changed.connect(_on_transform_changed)
%FinishBtn.pressed.connect(_on_finish_mask)
%ClearBtn.pressed.connect(_on_clear_mask)
%AddMaskBtn.pressed.connect(_on_add_mask)
# Settings
_wire_opacity_slider.value_changed.connect(func(_v): _uv_overlay.queue_redraw())
_wire_color_opt.clear()
for c in ["Black", "White", "Yellow", "Green"]: _wire_color_opt.add_item(c)
_wire_color_opt.selected = 0 # Black default
_wire_color_opt.item_selected.connect(func(_i):
_uv_overlay.queue_redraw()
if _inspected_mesh_name != "": _select_mesh(_inspected_mesh_name)
)
# Export
_export_folder_opt.clear(); for key in EXPORT_DIRS.keys(): _export_folder_opt.add_item(key)
_export_folder_opt.selected = 3; _export_folder_opt.item_selected.connect(func(_i): _update_export_prefix())
_export_mode.clear(); _export_mode.add_item("Texture Only (.png)"); _export_mode.add_item("Texture + Material"); _export_mode.selected = 0
%GenerateBtn.pressed.connect(_on_generate_pressed)
func _update_export_prefix():
var cname = _current_char_name().to_lower()
var folder = _export_folder_opt.get_item_text(_export_folder_opt.selected)
var cat_slug = "skin"
if "Clothing" in folder: cat_slug = "cloth"
elif "Gloves" in folder: cat_slug = "gloves"
elif "Hat" in folder: cat_slug = "hat"
_prefix_label.text = "%s_%s_" % [cname, cat_slug]
# ─── 3D SCENE ────────────────────────────────────────────────────────────────
func _setup_3d_scene():
# world_3d is already unique because of 'own_world_3d = true' in tscn
var cam := Camera3D.new(); cam.position = Vector3(0, 0.8, 1.8); cam.far = 100.0; _viewport_3d.add_child(cam); cam.call_deferred("look_at", Vector3(0,0.6,0))
var sun := DirectionalLight3D.new(); sun.rotation_degrees = Vector3(-45,45,0); sun.light_energy = 1.2; _viewport_3d.add_child(sun)
var env := WorldEnvironment.new(); env.environment = Environment.new(); env.environment.background_mode = Environment.BG_COLOR; env.environment.background_color = Color(0.12,0.12,0.12); env.environment.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR; env.environment.ambient_light_color = Color.WHITE; env.environment.ambient_light_energy = 0.4; _viewport_3d.add_child(env)
func _on_zoom_changed(v: float):
var cam = _viewport_3d.get_camera_3d()
if cam: cam.position.z = v; cam.call_deferred("look_at", Vector3(0,0.6,0))
func _on_3d_input(event: InputEvent):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT: _is_rotating = event.pressed; _last_mouse_pos = event.position
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: _inspect_at_pos(event.position)
elif event.button_index == MOUSE_BUTTON_WHEEL_UP: _zoom_slider.value -= 0.2
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: _zoom_slider.value += 0.2
if event is InputEventMouseMotion and _is_rotating:
var delta = event.position - _last_mouse_pos; _last_mouse_pos = event.position
if _char_preview: _char_preview.rotate_y(delta.x * 0.01)
func _inspect_at_pos(p: Vector2):
var cam = _viewport_3d.get_camera_3d(); if not cam or not _char_preview: return
var res = {"best": "", "min_dist": 1e10, "node": null}; _find_nearest_mesh(_char_preview, cam, p, res)
if res.node: _select_mesh(res.node.name)
func _find_nearest_mesh(n, c, p, r):
if n is MeshInstance3D and n.mesh and n.visible:
var center = n.global_transform * n.mesh.get_aabb().get_center()
if not c.is_position_behind(center):
var sp = c.unproject_position(center); var d = p.distance_to(sp)
if d < r.min_dist: r.min_dist = d; r.best = n.name; r.node = n
for ch in n.get_children(): _find_nearest_mesh(ch, c, p, r)
# ─── CHARACTER PREVIEW ───────────────────────────────────────────────────────
func _on_char_changed(_i): _update_character_preview()
func _current_char_name() -> String: return _character_opt.get_item_text(_character_opt.selected).to_lower()
func _update_character_preview():
if _char_preview: _char_preview.queue_free(); _char_preview = null
if _debug_wireframe: _debug_wireframe.queue_free(); _debug_wireframe = null
_inspected_mesh_name = ""; _inspected_label.text = ""
var cname = _current_char_name()
var path = "res://assets/characters/%s.glb" % cname.capitalize()
if not FileAccess.file_exists(path): return
var scene = load(path).instantiate(); _viewport_3d.add_child(scene); _char_preview = scene
# Force T-Pose
_force_t_pose(scene)
if not _char_cache.has(cname): _char_cache[cname] = {}
var tex = _get_embedded_texture(scene)
if not tex: tex = load("res://assets/characters/skins/tex/%s_cloth_ori_pant.png" % cname)
_uv_preview.texture = tex
_mesh_data.clear(); _collect_mesh_data(scene)
_build_scene_tree_ui(); _uv_overlay.queue_redraw()
func _collect_mesh_data(node: Node):
if node is MeshInstance3D and node.mesh:
var uvs := PackedVector2Array()
var tris := PackedVector2Array()
for s in node.mesh.get_surface_count():
var arr = node.mesh.surface_get_arrays(s)
var v_uvs = arr[Mesh.ARRAY_TEX_UV]; var idxs = arr[Mesh.ARRAY_INDEX]
if v_uvs:
var local_idxs = idxs if idxs else range(v_uvs.size())
for i in range(0, local_idxs.size()-2, 3):
var i0 = local_idxs[i]; var i1 = local_idxs[i+1]; var i2 = local_idxs[i+2]
var u0 = v_uvs[i0]; var u1 = v_uvs[i1]; var u2 = v_uvs[i2]
if _flip_uv: u0.y=1-u0.y; u1.y=1-u1.y; u2.y=1-u2.y
tris.append(u0); tris.append(u1); tris.append(u2)
var cname = _current_char_name()
var saved = _char_cache[cname].get(node.name, {})
var masks_arr = saved.get("masks", [])
if masks_arr.is_empty() and saved.has("mask"): masks_arr = [saved["mask"]] # Migration
var d = {
"name": node.name, "tris": tris, "node": node,
"category": saved.get("category", -1),
"fill_color": saved.get("fill_color", Color.WHITE),
"masks": masks_arr,
"img_path": saved.get("img_path", ""),
"img_pos": saved.get("img_pos", Vector2(0.5, 0.5)),
"img_scale": saved.get("img_scale", 1.0),
"img_rot": saved.get("img_rot", 0.0),
"tex": null,
"ref_path": saved.get("ref_path", ""),
"ref_tex": null,
"orig_tex": _get_material_texture(node)
}
if d.img_path != "": d.tex = load(d.img_path)
if d.ref_path != "": d.ref_tex = load(d.ref_path)
var mat = ShaderMaterial.new(); mat.shader = load(SHADER_PATH); mat.set_shader_parameter("albedo_texture", _uv_preview.texture)
node.set_surface_override_material(0, mat)
_mesh_data.append(d)
for c in node.get_children(): _collect_mesh_data(c)
func _get_mesh_data(name: String) -> Dictionary:
for d in _mesh_data:
if d.name == name: return d
return {}
# ─── SCENE TREE UI ───────────────────────────────────────────────────────────
func _build_scene_tree_ui():
for c in _mesh_list_vbox.get_children(): c.queue_free()
for d in _mesh_data:
var h := HBoxContainer.new(); _mesh_list_vbox.add_child(h)
var vis := Button.new(); vis.text = "👁"; vis.flat = true
vis.pressed.connect(_on_vis_pressed.bind(d.node, vis, d.name)); h.add_child(vis)
var col_dot := ColorRect.new(); col_dot.custom_minimum_size = Vector2(12, 20)
col_dot.color = d.fill_color if d.category >= 0 else Color(0.3,0.3,0.3,0.5); h.add_child(col_dot)
var btn := Button.new(); btn.text = d.name; btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL; btn.alignment = HORIZONTAL_ALIGNMENT_LEFT
btn.pressed.connect(_select_mesh.bind(d.name)); h.add_child(btn)
func _on_vis_pressed(node: Node3D, vis_btn: Button, mesh_name: String):
node.visible = !node.visible; vis_btn.modulate = Color.WHITE if node.visible else Color.GRAY
if _inspected_mesh_name == mesh_name and _debug_wireframe: _debug_wireframe.visible = node.visible
func _select_mesh(mesh_name: String):
_inspected_mesh_name = mesh_name; _inspected_label.text = "Selected: " + mesh_name
if _debug_wireframe: _debug_wireframe.queue_free(); _debug_wireframe = null
var d = _get_mesh_data(mesh_name)
if d.is_empty(): return
var wire := MeshInstance3D.new(); wire.mesh = d.node.mesh
d.node.add_child(wire); _debug_wireframe = wire
if d.node.skeleton != NodePath(""):
var skel_node = d.node.get_node(d.node.skeleton)
if skel_node: wire.skeleton = wire.get_path_to(skel_node)
if "skin" in d.node: wire.skin = d.node.skin
var wm := ShaderMaterial.new()
wm.shader = shader_from_string("shader_type spatial; render_mode unshaded, wireframe; uniform vec4 albedo:source_color; void fragment() { ALBEDO = albedo.rgb; ALPHA = albedo.a; }")
var col = _get_current_wire_color(); col.a = 0.5
wm.set_shader_parameter("albedo", col)
wire.set_surface_override_material(0, wm)
wire.visible = d.node.visible
_update_part_inspector()
_uv_overlay.queue_redraw()
func _update_part_inspector():
var d = _get_mesh_data(_inspected_mesh_name)
if d.is_empty(): return
_pi_name_lbl.text = _inspected_mesh_name
_pi_cat_opt.selected = d.category + 1
_pi_color_btn.color = d.fill_color
_pi_image_btn.text = d.img_path.get_file() if d.img_path != "" else "None"
_pi_ref_btn.text = d.ref_path.get_file() if d.ref_path != "" else "Default"
_update_mask_list_ui()
if d.ref_tex: _uv_preview.texture = d.ref_tex
elif d.orig_tex: _uv_preview.texture = d.orig_tex
else: _uv_preview.texture = null
%TransformVBox.visible = (d.img_path != "")
_pi_pos_x.value = d.img_pos.x; _pi_pos_y.value = d.img_pos.y
_pi_scale.value = d.img_scale; _pi_rot.value = d.img_rot
# ─── PART INSPECTOR CALLBACKS ────────────────────────────────────────────────
var _picking_mode: String = "sticker"
func _save_mesh_cache(d: Dictionary):
_char_cache[_current_char_name()][d.name] = {
"category": d.category, "fill_color": d.fill_color,
"masks": d.masks, "img_path": d.img_path, "ref_path": d.ref_path,
"img_pos": d.img_pos, "img_scale": d.img_scale, "img_rot": d.img_rot
}
func _on_pi_cat_selected(idx: int):
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.category = idx - 1; _save_mesh_cache(d); _build_scene_tree_ui(); _uv_overlay.queue_redraw()
func _on_pi_color_changed(col: Color):
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.fill_color = col; _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_pick_image(mode: String):
_picking_mode = mode
if not _file_dialog:
_file_dialog = FileDialog.new()
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
_file_dialog.access = FileDialog.ACCESS_RESOURCES
_file_dialog.add_filter("*.png, *.jpg, *.webp", "Images")
add_child(_file_dialog)
if _file_dialog.file_selected.is_connected(_on_image_selected): _file_dialog.file_selected.disconnect(_on_image_selected)
_file_dialog.file_selected.connect(_on_image_selected); _file_dialog.popup_centered_ratio(0.5)
func _on_image_selected(path: String):
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
if _picking_mode == "sticker": d.img_path = path; d.tex = load(path)
else: d.ref_path = path; d.ref_tex = load(path)
_update_part_inspector(); _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_clear_image():
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.img_path = ""; d.tex = null
_update_part_inspector(); _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_clear_ref():
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.ref_path = ""; d.ref_tex = null
_update_part_inspector(); _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_transform_changed(_v):
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.img_pos = Vector2(_pi_pos_x.value, _pi_pos_y.value)
d.img_scale = _pi_scale.value; d.img_rot = _pi_rot.value
_save_mesh_cache(d); _uv_overlay.queue_redraw()
# ─── MASK LAYERS ─────────────────────────────────────────────────────────────
func _update_mask_list_ui():
for c in %MaskList.get_children(): c.queue_free()
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
for i in range(d.masks.size()):
var hb = HBoxContainer.new()
var lbl = Label.new(); lbl.text = "Mask %s" % char(65 + i); lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var edit = Button.new(); edit.text = "Edit"; edit.pressed.connect(func(): _on_edit_mask(i))
var del = Button.new(); del.text = ""; del.pressed.connect(func(): _on_delete_mask(i))
hb.add_child(lbl); hb.add_child(edit); hb.add_child(del)
%MaskList.add_child(hb)
func _on_add_mask():
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.masks.append(PackedVector2Array())
_on_edit_mask(d.masks.size() - 1)
func _on_edit_mask(idx: int):
_current_mask_idx = idx
_drawing_mask = true
var d = _get_mesh_data(_inspected_mesh_name)
_mask_points = d.masks[idx]
%DrawingToolbar.visible = true
%DrawStatus.text = "Editing Mask %s..." % char(65 + idx)
_uv_overlay.queue_redraw()
func _on_delete_mask(idx: int):
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
d.masks.remove_at(idx)
if _current_mask_idx == idx: _on_finish_mask()
else: _update_mask_list_ui(); _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_start_mask(): _on_add_mask()
func _on_finish_mask():
_drawing_mask = false
var d = _get_mesh_data(_inspected_mesh_name); if d.is_empty(): return
if _current_mask_idx >= 0:
d.masks.remove_at(_current_mask_idx)
d.masks.insert(_current_mask_idx, _mask_points)
%DrawingToolbar.visible = false
_current_mask_idx = -1; _mask_points = PackedVector2Array()
_update_mask_list_ui(); _save_mesh_cache(d); _uv_overlay.queue_redraw()
func _on_clear_mask():
_mask_points = PackedVector2Array(); _uv_overlay.queue_redraw()
func _on_uv_input(event: InputEvent):
if not _uv_preview or not _uv_preview.texture: return
var vs = _uv_overlay.size; var ts = _uv_preview.texture.get_size()
var sc = min(vs.x/ts.x, vs.y/ts.y); var rs = ts*sc; var off = (vs-rs)*0.5
if _drawing_mask:
var uv = (event.position - off) / rs
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
# Check for drag
var best_dist = 0.05
_dragged_point_idx = -1
for i in range(_mask_points.size()):
var d = uv.distance_to(_mask_points[i])
if d < best_dist:
best_dist = d; _dragged_point_idx = i
if _dragged_point_idx == -1:
_mask_points.append(uv.clamp(Vector2.ZERO, Vector2.ONE))
else:
_dragged_point_idx = -1
_uv_overlay.queue_redraw()
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
# Delete point
var best_dist = 0.05; var to_del = -1
for i in range(_mask_points.size()):
var d = uv.distance_to(_mask_points[i])
if d < best_dist: best_dist = d; to_del = i
if to_del != -1:
_mask_points.remove_at(to_del)
_uv_overlay.queue_redraw()
elif event is InputEventMouseMotion:
if _dragged_point_idx != -1:
_mask_points[_dragged_point_idx] = uv.clamp(Vector2.ZERO, Vector2.ONE)
_uv_overlay.queue_redraw()
return
var d = _get_mesh_data(_inspected_mesh_name)
if d.is_empty() or not d.tex: return
if event is InputEventMouseButton:
var uv = (event.position - off) / rs
if event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
var dist = uv.distance_to(d.img_pos)
if dist < (0.1 / d.img_scale):
_gizmo_state = 1
if event.shift_pressed: _gizmo_state = 2
elif event.ctrl_pressed: _gizmo_state = 3
_gizmo_start_uv = uv
_gizmo_start_val = [d.img_pos, d.img_scale, d.img_rot]
else: _gizmo_state = 0
if event is InputEventMouseMotion and _gizmo_state > 0:
var uv = (event.position - off) / rs
var delta = uv - _gizmo_start_uv
if _gizmo_state == 1: d.img_pos = _gizmo_start_val[0] + delta
elif _gizmo_state == 2: d.img_pos = _gizmo_start_val[0]; d.img_scale = max(0.01, _gizmo_start_val[1] + delta.x * 2.0)
elif _gizmo_state == 3: d.img_rot = _gizmo_start_val[2] + delta.x * 180.0
_pi_pos_x.value = d.img_pos.x; _pi_pos_y.value = d.img_pos.y
_pi_scale.value = d.img_scale; _pi_rot.value = d.img_rot
_save_mesh_cache(d); _uv_overlay.queue_redraw()
# ─── UV OVERLAY DRAW ─────────────────────────────────────────────────────────
func _on_uv_overlay_draw():
if not _uv_preview or not _uv_preview.texture: return
var vs = _uv_overlay.size; var ts = _uv_preview.texture.get_size()
var sc = min(vs.x/ts.x, vs.y/ts.y); var rs = ts*sc; var off = (vs-rs)*0.5
if _hide_ref:
for d in _mesh_data:
if d.category < 0: continue
var tris = d.tris
for i in range(0, tris.size()-2, 3):
var poly = PackedVector2Array([off + tris[i]*rs, off + tris[i+1]*rs, off + tris[i+2]*rs])
_uv_overlay.draw_colored_polygon(poly, d.fill_color)
else:
if _show_all_uvs:
for d in _mesh_data:
if d.name == _inspected_mesh_name: continue
_draw_mesh_wireframe(d, off, rs, Color(0.2, 0.2, 0.2, 0.3))
for d in _mesh_data:
if d.category < 0 or d.name == _inspected_mesh_name: continue
_draw_mesh_filled(d, off, rs, Color(d.fill_color.r, d.fill_color.g, d.fill_color.b, 0.15))
_draw_mesh_wireframe(d, off, rs, Color(d.fill_color.r, d.fill_color.g, d.fill_color.b, 0.4))
if _inspected_mesh_name != "":
var d = _get_mesh_data(_inspected_mesh_name)
if not d.is_empty():
_draw_mesh_filled(d, off, rs, Color(1, 1, 1, 0.03))
_draw_mesh_wireframe(d, off, rs, Color(1, 0.8, 0.1, 1.0), 2.0)
for m in d.masks:
if m.size() >= 3:
var ps = _to_screen(m, rs, off)
if Geometry2D.triangulate_polygon(ps).size() > 0:
_uv_overlay.draw_colored_polygon(ps, Color(0, 1, 0, 0.2))
_uv_overlay.draw_polyline(ps, Color(0, 1, 0, 0.5), 1.5, true)
if _current_mask_idx >= 0 and _mask_points.size() > 0:
var ps = _to_screen(_mask_points, rs, off)
var mouse_uv = (_uv_overlay.get_local_mouse_position() - off) / rs
for i in range(ps.size()):
var is_hover = mouse_uv.distance_to(_mask_points[i]) < 0.05
_uv_overlay.draw_circle(ps[i], 5 if is_hover else 3, Color.CYAN if is_hover else Color.YELLOW)
if ps.size() > 1:
_uv_overlay.draw_polyline(ps, Color.YELLOW, 2.0)
_uv_overlay.draw_line(ps[-1], ps[0], Color(1, 1, 0, 0.3), 1.0)
for d in _mesh_data:
if d.category >= 0 and d.tex:
var rot_rad = deg_to_rad(d.img_rot)
var rect = Rect2(off + (d.img_pos - Vector2(0.5,0.5)*d.img_scale)*rs, Vector2(d.img_scale, d.img_scale)*rs)
_uv_overlay.draw_set_transform(rect.get_center(), rot_rad, Vector2.ONE)
_uv_overlay.draw_texture_rect(d.tex, Rect2(-rect.size*0.5, rect.size), false)
if d.name == _inspected_mesh_name:
var g_col = Color.YELLOW if _gizmo_state > 0 else Color.WHITE
_uv_overlay.draw_rect(Rect2(-rect.size*0.5, rect.size), g_col, false, 2.0)
_uv_overlay.draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
func _draw_mesh_wireframe(d: Dictionary, off: Vector2, rs: Vector2, col: Color, width: float = 1.0):
var tris = d.tris
var draw_col = _get_current_wire_color(); draw_col.a *= _wire_opacity_slider.value
for i in range(0, tris.size()-2, 3):
_uv_overlay.draw_line(off + tris[i]*rs, off + tris[i+1]*rs, draw_col, width)
_uv_overlay.draw_line(off + tris[i+1]*rs, off + tris[i+2]*rs, draw_col, width)
_uv_overlay.draw_line(off + tris[i+2]*rs, off + tris[i]*rs, draw_col, width)
func _draw_mesh_filled(d: Dictionary, off: Vector2, rs: Vector2, col: Color):
for i in range(0, d.tris.size()-2, 3):
_uv_overlay.draw_colored_polygon(PackedVector2Array([off+d.tris[i]*rs, off+d.tris[i+1]*rs, off+d.tris[i+2]*rs]), col)
# ─── GENERATE & EXPORT ───────────────────────────────────────────────────────
func _on_generate_pressed() -> void:
var img = _uv_preview.texture.get_image()
if img.is_compressed(): img.decompress()
var w = img.get_width(); var h = img.get_height()
# Transparent output — only assigned regions get color
var out = Image.create(w, h, false, Image.FORMAT_RGBA8)
for d in _mesh_data:
if d.category < 0: continue
var fill: Color = d.fill_color
var masks = d.masks
var tris = d.tris
var sticker: Image = null
if d.tex: sticker = d.tex.get_image(); if sticker.is_compressed(): sticker.decompress()
for ti in range(0, tris.size()-2, 3):
_rasterize_tri_aa(img, out, tris[ti], tris[ti+1], tris[ti+2], fill, masks, w, h, sticker, d)
var target_key = _export_folder_opt.get_item_text(_export_folder_opt.selected)
var out_dir = EXPORT_DIRS.get(target_key, BASE_TEX_DIR)
for d in [out_dir, BASE_TEX_DIR]:
if not DirAccess.dir_exists_absolute(d):
DirAccess.make_dir_recursive_absolute(d)
var prefix = _prefix_label.text
var ename = _export_name.text.strip_edges()
if ename.is_empty(): ename = "unnamed"
var png_name = prefix + ename
var png_path = BASE_TEX_DIR + png_name + ".png"
var err = out.save_png(png_path)
var result_msg = ""
if err == OK:
result_msg = "✅ Saved: " + png_name + ".png"
else:
result_msg = "❌ PNG Save Error: " + str(err)
_status_label.text = result_msg; _status_label.modulate = Color.RED; return
if _export_mode.selected == 1:
var tex = ImageTexture.create_from_image(out)
var mat := StandardMaterial3D.new(); mat.albedo_texture = tex
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA_SCISSOR; mat.alpha_scissor_threshold = 0.5
var parts = prefix.split("_")
var mat_name = parts[0] + "_mat_" + parts[1] + "_" + ename
var mat_err = ResourceSaver.save(mat, out_dir + mat_name + ".tres")
if mat_err == OK:
result_msg += " + " + mat_name + ".tres"
else:
result_msg += " (❌ Mat Error: " + str(mat_err) + ")"
_status_label.text = result_msg; _status_label.modulate = Color.GREEN
# Force filesystem refresh so they show up in editor
if Engine.is_editor_hint():
var ep = EditorInterface.get_resource_filesystem()
if ep: ep.scan()
func _rasterize_tri_aa(src: Image, dst: Image, u0: Vector2, u1: Vector2, u2: Vector2, col: Color, masks: Array, w: int, h: int, sticker: Image = null, d: Dictionary = {}):
var min_x = int(min(u0.x, min(u1.x, u2.x)) * w); var max_x = int(max(u0.x, max(u1.x, u2.x)) * w)
var min_y = int(min(u0.y, min(u1.y, u2.y)) * h); var max_y = int(max(u0.y, max(u1.y, u2.y)) * h)
min_x = clamp(min_x-1,0,w-1); max_x = clamp(max_x+1,0,w-1); min_y = clamp(min_y-1,0,h-1); max_y = clamp(max_y+1,0,h-1)
for y in range(min_y, max_y + 1):
for x in range(min_x, max_x + 1):
var uv = Vector2(float(x)/w, float(y)/h)
if _point_in_triangle(uv, u0, u1, u2):
var mask_alpha = 1.0
if not masks.is_empty():
# 4x4 Supersampling
var hits = 0.0
for sy in range(4):
for sx in range(4):
var sub_uv = uv + Vector2(sx-1.5, sy-1.5) / Vector2(w*4, h*4)
var inside = false
for m in masks:
if _point_in_polygon(sub_uv, m): inside = true; break
if inside: hits += 1.0
mask_alpha = hits / 16.0
if mask_alpha > 0.001:
var final_col = col
if sticker:
var s_uv = (uv - d.img_pos).rotated(-deg_to_rad(d.img_rot)) / d.img_scale + Vector2(0.5, 0.5)
if s_uv.x >= 0 and s_uv.x <= 1 and s_uv.y >= 0 and s_uv.y <= 1:
var sc = sticker.get_pixelv(s_uv * Vector2(sticker.get_width()-1, sticker.get_height()-1))
final_col = col.lerp(sc, sc.a)
var old = dst.get_pixel(x, y)
dst.set_pixel(x, y, old.lerp(final_col, mask_alpha))
func _point_in_triangle(p: Vector2, a: Vector2, b: Vector2, c: Vector2) -> bool:
var d0 = (b-a).cross(p-a); var d1 = (c-b).cross(p-b); var d2 = (a-c).cross(p-c)
return ((d0>=0 and d1>=0 and d2>=0) or (d0<=0 and d1<=0 and d2<=0))
func _point_in_polygon(p: Vector2, poly: PackedVector2Array) -> bool:
var inside = false; var n = poly.size(); var j = n - 1
for i in n:
var pi = poly[i]; var pj = poly[j]
if ((pi.y > p.y) != (pj.y > p.y)) and (p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x):
inside = !inside
j = i
return inside
# ─── HELPERS ─────────────────────────────────────────────────────────────────
func _get_embedded_texture(n):
if n is MeshInstance3D and n.mesh:
var m = n.get_surface_override_material(0); if not m: m = n.mesh.surface_get_material(0)
if m and "albedo_texture" in m and m.albedo_texture: return m.albedo_texture
for ch in n.get_children(): var t = _get_embedded_texture(ch); if t: return t
return null
func _mk_label(t: String) -> Label:
var l := Label.new(); l.text = t; return l
# ─── PRESETS ─────────────────────────────────────────────────────────────────
func _on_save_preset():
var cname = _current_char_name(); if cname == "": return
var data = _char_cache[cname]
var out_data = {}
for mesh_name in data:
var d = data[mesh_name]
out_data[mesh_name] = {
"category": d.category,
"fill_color": d.fill_color.to_html(),
"masks": d.masks.map(func(m): return Array(m)),
"img_path": d.img_path,
"ref_path": d.ref_path,
"img_pos": [d.img_pos.x, d.img_pos.y],
"img_scale": d.img_scale,
"img_rot": d.img_rot
}
var f = FileAccess.open(PRESET_DIR + cname + "_preset.json", FileAccess.WRITE)
f.store_string(JSON.stringify(out_data, "\t"))
_status_label.text = "Preset Saved: " + cname + "_preset.json"; _status_label.modulate = Color.GREEN
func _on_load_preset():
var cname = _current_char_name(); if cname == "": return
var path = PRESET_DIR + cname + "_preset.json"
if not FileAccess.file_exists(path): _status_label.text = "No preset found for " + cname; _status_label.modulate = Color.RED; return
var f = FileAccess.open(path, FileAccess.READ)
var raw = JSON.parse_string(f.get_as_text())
if not raw: return
var cache = {}
for mesh_name in raw:
var d = raw[mesh_name]
var masks_arr = d.get("masks", [])
if masks_arr.is_empty() and d.has("mask"): masks_arr = [d["mask"]]
cache[mesh_name] = {
"category": int(d.category),
"fill_color": Color.html(d.fill_color),
"masks": masks_arr.map(func(m): return PackedVector2Array(m)),
"img_path": d.img_path,
"ref_path": d.get("ref_path", ""),
"img_pos": Vector2(d.img_pos[0], d.img_pos[1]),
"img_scale": float(d.img_scale),
"img_rot": float(d.img_rot)
}
_char_cache[cname] = cache
_update_character_preview()
_status_label.text = "Preset Loaded: " + cname; _status_label.modulate = Color.CYAN
func _force_t_pose(node: Node):
if node is AnimationPlayer:
if node.has_animation("RESET"):
node.play("RESET")
node.advance(0)
node.stop()
if node is Skeleton3D:
for i in node.get_bone_count():
node.reset_bone_pose(i)
for c in node.get_children(): _force_t_pose(c)
func _get_material_texture(node: Node) -> Texture2D:
if node is MeshInstance3D and node.mesh:
var mat = node.get_surface_override_material(0)
if not mat: mat = node.mesh.surface_get_material(0)
if mat is StandardMaterial3D or mat is ORMMaterial3D:
return mat.albedo_texture
elif mat is ShaderMaterial:
# Try to find a parameter named albedo or main_texture
for p in ["albedo_texture", "main_texture", "texture_albedo"]:
var t = mat.get_shader_parameter(p)
if t is Texture2D: return t
return null
func shader_from_string(code: String) -> Shader:
var s = Shader.new(); s.code = code; return s
func _get_current_wire_color() -> Color:
match _wire_color_opt.selected:
0: return Color.BLACK
1: return Color.WHITE
2: return Color.YELLOW
3: return Color.GREEN
return Color.YELLOW
func _to_screen(pts: PackedVector2Array, rs: Vector2, off: Vector2) -> PackedVector2Array:
var out := PackedVector2Array()
for p in pts: out.append(p * rs + off)
return out
@@ -0,0 +1 @@
uid://dbcyurv4m7mka
+137
View File
@@ -0,0 +1,137 @@
extends Control
## FragmentCraftPanel — Shows all craftable skins and their fragment requirements.
## Linked from GachaPanel via the "🧩 Fragment Craft" button.
signal closed
# ─── Node refs ───────────────────────────────────────────────────────────────
@onready var back_btn := %BackBtn as Button
@onready var recipe_list := %RecipeList as VBoxContainer
@onready var status_label := %StatusLabel as Label
@onready var frag_balance := %FragBalance as Label
const FRAG_ICONS := {
"frag_common": "",
"frag_uncommon": "🟩",
"frag_rare": "🟦"
}
# ─── Lifecycle ────────────────────────────────────────────────────────────────
func _ready() -> void:
back_btn.pressed.connect(_on_close)
func show_panel() -> void:
show()
_refresh()
func _refresh() -> void:
_update_frag_balance()
_rebuild_recipe_list()
# ─── Fragment balance header ──────────────────────────────────────────────────
func _update_frag_balance() -> void:
var frags: Dictionary = UserProfileManager.fragments
var parts: Array = []
for fid in ["frag_common", "frag_uncommon", "frag_rare"]:
var icon: String = FRAG_ICONS.get(fid, "?")
var count: int = frags.get(fid, 0)
parts.append("%s ×%d" % [icon, count])
frag_balance.text = " ".join(parts)
# ─── Recipe cards ─────────────────────────────────────────────────────────────
func _rebuild_recipe_list() -> void:
for c in recipe_list.get_children(): c.queue_free()
await get_tree().process_frame
var recipes: Dictionary = GachaManager.get_all_recipes()
for recipe_id in recipes:
var recipe: Dictionary = recipes[recipe_id]
var card := _make_recipe_card(recipe_id, recipe)
recipe_list.add_child(card)
func _make_recipe_card(recipe_id: String, recipe: Dictionary) -> PanelContainer:
var can_craft: bool = GachaManager.can_craft(recipe_id)
var frags: Dictionary = UserProfileManager.fragments
var panel := PanelContainer.new()
panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 14)
margin.add_theme_constant_override("margin_top", 10)
margin.add_theme_constant_override("margin_right", 14)
margin.add_theme_constant_override("margin_bottom", 10)
panel.add_child(margin)
var hbox := HBoxContainer.new()
hbox.add_theme_constant_override("separation", 14)
margin.add_child(hbox)
# Left info
var vbox := VBoxContainer.new()
vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
vbox.add_theme_constant_override("separation", 4)
hbox.add_child(vbox)
var name_lbl := Label.new()
name_lbl.text = recipe.get("name", recipe_id)
name_lbl.add_theme_font_size_override("font_size", 16)
name_lbl.add_theme_color_override("font_color", Color(0.9, 0.8, 0.3))
vbox.add_child(name_lbl)
var char_cat_lbl := Label.new()
char_cat_lbl.text = "%s%s" % [recipe.get("character", "All"), recipe.get("category", "").capitalize()]
char_cat_lbl.add_theme_font_size_override("font_size", 11)
char_cat_lbl.add_theme_color_override("font_color", Color(0.65, 0.65, 0.65))
vbox.add_child(char_cat_lbl)
# Fragment cost row
var cost_hbox := HBoxContainer.new()
cost_hbox.add_theme_constant_override("separation", 12)
vbox.add_child(cost_hbox)
var cost: Dictionary = recipe.get("cost", {})
for fid in ["frag_common", "frag_uncommon", "frag_rare"]:
if not cost.has(fid): continue
var needed: int = cost[fid]
var have: int = frags.get(fid, 0)
var icon: String = FRAG_ICONS.get(fid, "?")
var cost_lbl := Label.new()
cost_lbl.text = "%s %d/%d" % [icon, have, needed]
cost_lbl.add_theme_font_size_override("font_size", 13)
cost_lbl.add_theme_color_override("font_color",
Color(0.4, 1.0, 0.5) if have >= needed else Color(1.0, 0.4, 0.4))
cost_hbox.add_child(cost_lbl)
# Craft button
var craft_btn := Button.new()
craft_btn.text = "🔨 Craft"
craft_btn.custom_minimum_size = Vector2(100, 40)
craft_btn.disabled = not can_craft
if not can_craft:
craft_btn.modulate = Color(0.5, 0.5, 0.5, 0.7)
craft_btn.pressed.connect(_on_craft_pressed.bind(recipe_id, panel))
hbox.add_child(craft_btn)
return panel
# ─── Craft action ─────────────────────────────────────────────────────────────
func _on_craft_pressed(recipe_id: String, _card: PanelContainer) -> void:
var ok := GachaManager.craft(recipe_id)
if ok:
var recipes := GachaManager.get_all_recipes()
var name: String = recipes.get(recipe_id, {}).get("name", recipe_id)
_set_status("✅ Crafted: %s!" % name, Color(0.4, 1.0, 0.4))
_refresh()
else:
_set_status("❌ Not enough fragments.", Color(1.0, 0.4, 0.4))
func _set_status(msg: String, col: Color = Color.WHITE) -> void:
status_label.add_theme_color_override("font_color", col)
status_label.text = msg
await get_tree().create_timer(3.0).timeout
if status_label.text == msg: status_label.text = ""
func _on_close() -> void:
hide()
closed.emit()
+1
View File
@@ -0,0 +1 @@
uid://cnenx8f7cftrs
+212
View File
@@ -0,0 +1,212 @@
extends Control
## GachaPanel — Two-banner gacha interface.
## Banners: Star (✦) and Gold (▤)
## Pull results shown in animated card reveal.
signal closed
# ─── Node refs ───────────────────────────────────────────────────────────────
@onready var back_btn := %BackBtn as Button
@onready var star_tab_btn := %StarTabBtn as Button
@onready var gold_tab_btn := %GoldTabBtn as Button
@onready var banner_label := %BannerLabel as Label
@onready var balance_label := %BalanceLabel as Label
@onready var pity_label := %PityLabel as Label
@onready var pull_1_btn := %Pull1Btn as Button
@onready var pull_10_btn := %Pull10Btn as Button
@onready var cost_1_label := %Cost1Label as Label
@onready var cost_10_label := %Cost10Label as Label
@onready var rates_label := %RatesLabel as Label
@onready var result_panel := %ResultPanel as PanelContainer
@onready var result_grid := %ResultGrid as GridContainer
@onready var close_result_btn := %CloseResultBtn as Button
@onready var craft_btn := %CraftBtn as Button
@onready var status_label := %StatusLabel as Label
# ─── State ───────────────────────────────────────────────────────────────────
var _current_banner: String = "star"
var _pulling: bool = false
const RARITY_COLORS := {
"common": Color(0.80, 0.80, 0.80),
"uncommon": Color(0.30, 0.85, 0.35),
"rare": Color(0.20, 0.55, 1.00),
"real_prize": Color(1.00, 0.75, 0.10)
}
const RARITY_LABELS := {
"common": "Common",
"uncommon": "Uncommon",
"rare": "Rare",
"real_prize": "✨ REAL PRIZE ✨"
}
# ─── Lifecycle ────────────────────────────────────────────────────────────────
func _ready() -> void:
back_btn.pressed.connect(_on_close)
star_tab_btn.pressed.connect(func(): _switch_banner("star"))
gold_tab_btn.pressed.connect(func(): _switch_banner("gold"))
pull_1_btn.pressed.connect(func(): _do_pull(1))
pull_10_btn.pressed.connect(func(): _do_pull(10))
close_result_btn.pressed.connect(func(): result_panel.hide())
craft_btn.pressed.connect(_on_open_craft)
result_panel.hide()
_switch_banner("star")
func show_panel() -> void:
show()
_refresh_ui()
# ─── Banner switching ─────────────────────────────────────────────────────────
func _switch_banner(id: String) -> void:
_current_banner = id
star_tab_btn.modulate = Color(1.3, 1.1, 0.3) if id == "star" else Color.WHITE
gold_tab_btn.modulate = Color(1.3, 1.1, 0.3) if id == "gold" else Color.WHITE
_refresh_ui()
func _refresh_ui() -> void:
var gd: Dictionary = GachaManager.data
var banner: Dictionary = gd.get("banners", {}).get(_current_banner, {})
if banner.is_empty(): return
var currency: String = banner.get("currency", "star")
var icon: String = "" if currency == "star" else ""
var bal: int = GachaManager.get_balance(_current_banner)
var pity: int = GachaManager.get_pity(_current_banner)
var pity_at: int = banner.get("pity_at", 90)
var c1: int = banner.get("pull_1_cost", 0)
var c10: int = banner.get("pull_10_cost", 0)
var rates: Dictionary = banner.get("rates", {})
banner_label.text = banner.get("name", "Banner")
balance_label.text = "%s %d" % [icon, bal]
pity_label.text = "Pity: %d / %d" % [pity, pity_at]
cost_1_label.text = "%s %d" % [icon, c1]
cost_10_label.text = "%s %d" % [icon, c10]
pull_1_btn.disabled = (bal < c1) or _pulling
pull_10_btn.disabled = (bal < c10) or _pulling
var real_pool: Array = gd.get("pools", {}).get("real_prize", [])
var real_names: Array = []
for rid in real_pool:
var rd = gd.get("real_prize_catalog", {}).get(rid, {})
real_names.append(rd.get("name", rid))
rates_label.text = (
"Common %.0f%% Uncommon %.0f%% Rare %.0f%% ✨Real Prize %.1f%%\n" +
"Guaranteed Real Prize every %d pulls (current pity: %d)\n\n" +
"✨ Exclusive Real Prizes:\n" + "\n".join(real_names.map(func(n): return "" + n))
) % [
rates.get("common", 0) * 100,
rates.get("uncommon", 0) * 100,
rates.get("rare", 0) * 100,
rates.get("real_prize", 0) * 100,
pity_at, pity
]
# ─── Pull ─────────────────────────────────────────────────────────────────────
func _do_pull(count: int) -> void:
if _pulling: return
_pulling = true
status_label.text = "Rolling..."
var results: Array = await _run_pull(count)
_pulling = false
if results.is_empty():
status_label.text = "❌ Not enough currency!"
_refresh_ui()
return
status_label.text = ""
_refresh_ui()
_show_results(results)
func _run_pull(count: int) -> Array:
# Yield one frame so UI updates first
await get_tree().process_frame
return GachaManager.pull(_current_banner, count)
# ─── Result display ───────────────────────────────────────────────────────────
func _show_results(results: Array) -> void:
# Clear old cards
for c in result_grid.get_children(): c.queue_free()
await get_tree().process_frame
result_panel.show()
for res in results:
var card := _make_result_card(res)
result_grid.add_child(card)
# Staggered reveal
await get_tree().create_timer(0.08).timeout
func _make_result_card(res: Dictionary) -> PanelContainer:
var rarity: String = res.get("rarity", "common")
var col: Color = RARITY_COLORS.get(rarity, Color.WHITE)
var label_txt: String = RARITY_LABELS.get(rarity, rarity.capitalize())
var panel := PanelContainer.new()
panel.custom_minimum_size = Vector2(110, 130)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 8)
margin.add_theme_constant_override("margin_top", 8)
margin.add_theme_constant_override("margin_right", 8)
margin.add_theme_constant_override("margin_bottom", 8)
panel.add_child(margin)
var vbox := VBoxContainer.new()
vbox.alignment = BoxContainer.ALIGNMENT_CENTER
margin.add_child(vbox)
# Rarity icon
var icon_lbl := Label.new()
icon_lbl.text = _rarity_icon(rarity)
icon_lbl.add_theme_font_size_override("font_size", 36)
icon_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
icon_lbl.add_theme_color_override("font_color", col)
vbox.add_child(icon_lbl)
# Item name
var name_lbl := Label.new()
name_lbl.text = res.get("name", "?")
name_lbl.add_theme_font_size_override("font_size", 11)
name_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
name_lbl.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
name_lbl.add_theme_color_override("font_color", col)
vbox.add_child(name_lbl)
# Rarity label
var rar_lbl := Label.new()
rar_lbl.text = label_txt
rar_lbl.add_theme_font_size_override("font_size", 9)
rar_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
rar_lbl.add_theme_color_override("font_color", col.lerp(Color.WHITE, 0.3))
vbox.add_child(rar_lbl)
# Flash animation
panel.modulate.a = 0.0
var tween := create_tween()
tween.tween_property(panel, "modulate:a", 1.0, 0.25)
if rarity == "real_prize":
tween.tween_property(panel, "modulate", Color(1.4, 1.3, 0.5, 1.0), 0.2)
tween.tween_property(panel, "modulate", Color.WHITE, 0.3)
return panel
func _rarity_icon(rarity: String) -> String:
match rarity:
"common": return ""
"uncommon": return "🟩"
"rare": return "🟦"
"real_prize": return ""
return ""
# ─── Craft link ───────────────────────────────────────────────────────────────
func _on_open_craft() -> void:
hide()
# Find or load the fragment craft panel in the scene tree
var main = get_tree().current_scene
var fcp = main.get_node_or_null("FragmentCraftPanel")
if fcp:
fcp.show_panel()
func _on_close() -> void:
hide()
closed.emit()
+1
View File
@@ -0,0 +1 @@
uid://clkxaudy5hxfj
+14 -1
View File
@@ -33,6 +33,7 @@ signal profile_updated
@onready var costume_tab_btn := %CostumeTabBtn as Button @onready var costume_tab_btn := %CostumeTabBtn as Button
@onready var glove_tab_btn := %GloveTabBtn as Button @onready var glove_tab_btn := %GloveTabBtn as Button
@onready var acc_tab_btn := %AccTabBtn as Button @onready var acc_tab_btn := %AccTabBtn as Button
@onready var frag_tab_btn := %FragTabBtn as Button
@onready var drag_zone := %DragZone as Control @onready var drag_zone := %DragZone as Control
@onready var character_root := %CharacterRoot as Node3D @onready var character_root := %CharacterRoot as Node3D
@onready var char_left_btn := %CharLeftBtn as Button @onready var char_left_btn := %CharLeftBtn as Button
@@ -173,6 +174,7 @@ func _connect_signals() -> void:
costume_tab_btn.pressed.connect(func(): _on_category_tab_pressed("costume")) costume_tab_btn.pressed.connect(func(): _on_category_tab_pressed("costume"))
glove_tab_btn.pressed.connect(func(): _on_category_tab_pressed("glove")) glove_tab_btn.pressed.connect(func(): _on_category_tab_pressed("glove"))
acc_tab_btn.pressed.connect(func(): _on_category_tab_pressed("accessory")) acc_tab_btn.pressed.connect(func(): _on_category_tab_pressed("accessory"))
frag_tab_btn.pressed.connect(func(): _on_category_tab_pressed("fragment"))
# Item grid slot buttons # Item grid slot buttons
for i in _item_slots.size(): for i in _item_slots.size():
@@ -248,13 +250,18 @@ func _highlight_active_tab() -> void:
"head": head_tab_btn, "head": head_tab_btn,
"costume": costume_tab_btn, "costume": costume_tab_btn,
"glove": glove_tab_btn, "glove": glove_tab_btn,
"accessory": acc_tab_btn "accessory": acc_tab_btn,
"fragment": frag_tab_btn
} }
for cat: String in map: for cat: String in map:
(map[cat] as Button).modulate = Color(1.3, 1.3, 0.4, 1) if cat == _current_category else Color.WHITE (map[cat] as Button).modulate = Color(1.3, 1.3, 0.4, 1) if cat == _current_category else Color.WHITE
func _rebuild_category_items() -> void: func _rebuild_category_items() -> void:
_category_items.clear() _category_items.clear()
# Fragment tab handled separately
if _current_category == "fragment":
_rebuild_fragment_items()
return
var prefix := _current_category + "_" var prefix := _current_category + "_"
# Resolve the current character's node name (e.g. "Copper" → "Oldpop") # Resolve the current character's node name (e.g. "Copper" → "Oldpop")
var current_char_display: String = CHARACTERS[_loadout_index] var current_char_display: String = CHARACTERS[_loadout_index]
@@ -283,6 +290,12 @@ func _rebuild_category_items() -> void:
# ───────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────
# Item grid # Item grid
# ───────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────
func _rebuild_fragment_items() -> void:
var frags: Dictionary = UserProfileManager.fragments
for fid in ["frag_common", "frag_uncommon", "frag_rare"]:
var count: int = frags.get(fid, 0)
if count > 0: _category_items.append(fid)
func _populate_item_grid() -> void: func _populate_item_grid() -> void:
var start: int = _current_page * ITEMS_PER_PAGE var start: int = _current_page * ITEMS_PER_PAGE
var total: int = _category_items.size() var total: int = _category_items.size()
+12 -6
View File
@@ -69,14 +69,20 @@ var ADMIN_ROLES = ["admin", "moderator", "owner"];
// [BEGIN_SHOP_CATALOG_DEFS] // [BEGIN_SHOP_CATALOG_DEFS]
var SHOP_CATALOG_DEFS = [ var SHOP_CATALOG_DEFS = [
// ── HEAD ──────────────────────────────────────────────────────────── // ── HEAD ────────────────────────────────────────────────────────────
{ id: "example-hat", name: "Example Hat", category: "head", gold: 0, star: 0, rarity: "Common", character: "Oldpop" }, { id: "oldpop-blue-hat", name: "Oldpop Blue Hat", category: "head", gold: 100, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-green-hat", name: "Oldpop Green Hat", category: "head", gold: 100, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-red-hat", name: "Oldpop Red Hat", category: "head", gold: 100, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-yellow-hat", name: "Oldpop Yellow Hat", category: "head", gold: 100, star: 0, rarity: "Common", character: "Oldpop" },
// ── COSTUME ──────────────────────────────────────────────────────────── // ── COSTUME ────────────────────────────────────────────────────────────
{ id: "oldpop-grey-pant", name: "Copper Grey Pant", category: "costume", gold: 200, star: 0, rarity: "Common", character: "Oldpop" }, { id: "oldpop-og-pant", name: "Copper OG Pant", category: "costume", gold: 0, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-clothing-original", name: "Copper Original Pants", category: "costume", gold: 0, star: 0, rarity: "Common", character: "Oldpop" }, { id: "oldpop-grey-pant", name: "Copper Grey Pant", category: "costume", gold: 150, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-red-pant", name: "Copper Red Pant", category: "costume", gold: 150, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-yellow-pant", name: "Copper Yellow Pant", category: "costume", gold: 150, star: 0, rarity: "Common", character: "Oldpop" },
// ── GLOVE ──────────────────────────────────────────────────────────── // ── GLOVE ────────────────────────────────────────────────────────────
{ id: "example-gloves", name: "Example Gloves", category: "glove", gold: 150, star: 0, rarity: "Common", character: "Oldpop" }, { id: "oldpop-blue-gloves", name: "Oldpop Blue Gloves", category: "glove", gold: 75, star: 0, rarity: "Common", character: "Oldpop" },
// ── COSTUME ──────────────────────────────────────────────────────────── { id: "oldpop-green-gloves", name: "Oldpop Green Gloves", category: "glove", gold: 75, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-red-pant", name: "Copper Red Pant", category: "costume", gold: 200, star: 0, rarity: "Rare", character: "Oldpop" }, { id: "oldpop-red-gloves", name: "Oldpop Red Gloves", category: "glove", gold: 75, star: 0, rarity: "Common", character: "Oldpop" },
{ id: "oldpop-yellow-gloves", name: "Oldpop Yellow Gloves", category: "glove", gold: 75, star: 0, rarity: "Common", character: "Oldpop" },
]; ];
// [END_SHOP_CATALOG_DEFS] // [END_SHOP_CATALOG_DEFS]