4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
13
.gitattributes
vendored
Normal file
13
.gitattributes
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
||||
|
||||
# files stored in LFS
|
||||
*.glb filter=lfs diff=lfs merge=lfs -text
|
||||
*.obj filter=lfs diff=lfs merge=lfs -text
|
||||
*.exr filter=lfs diff=lfs merge=lfs -text
|
||||
*.avi filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogv filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.blend filter=lfs diff=lfs merge=lfs -text
|
||||
*.blend1 filter=lfs diff=lfs merge=lfs -text
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
/android/
|
1
icon.svg
Normal file
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
After Width: | Height: | Size: 994 B |
37
icon.svg.import
Normal file
37
icon.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cnvhkptdeevyy"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
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/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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
20
project.godot
Normal file
20
project.godot
Normal file
@@ -0,0 +1,20 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="kairo"
|
||||
run/main_scene="uid://c37m0t4dwnwbn"
|
||||
config/features=PackedStringArray("4.4", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[autoload]
|
||||
|
||||
GameState="*res://scripts/autoload/game_state.gd"
|
27
resources/data/boosters/booster.gd
Normal file
27
resources/data/boosters/booster.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
extends Resource
|
||||
class_name Booster
|
||||
|
||||
|
||||
|
||||
@export var name: String
|
||||
@export var counts: Dictionary = { "Common": 4, "Rare": 1 }
|
||||
@export var cards: Array[Card] = []
|
||||
|
||||
func draw() -> Array[Card]:
|
||||
var res: Array[Card] = []
|
||||
|
||||
# Group cards by rarity
|
||||
var rarity_pool: Dictionary = {}
|
||||
for card in cards:
|
||||
if not rarity_pool.has(card.rarity):
|
||||
rarity_pool[card.rarity] = []
|
||||
rarity_pool[card.rarity].append(card)
|
||||
|
||||
# Draw based on rarity count
|
||||
for rarity in counts.keys():
|
||||
var count = counts[rarity]
|
||||
var pool = rarity_pool.get(rarity, [])
|
||||
for i in range(min(count, pool.size())):
|
||||
res.append(pool.pick_random())
|
||||
|
||||
return res
|
1
resources/data/boosters/booster.gd.uid
Normal file
1
resources/data/boosters/booster.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d2vr5ocvib663
|
15
resources/data/boosters/new_base_booster.tres
Normal file
15
resources/data/boosters/new_base_booster.tres
Normal file
@@ -0,0 +1,15 @@
|
||||
[gd_resource type="Resource" script_class="Booster" load_steps=4 format=3 uid="uid://c63rkr0cudnom"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://5pqr71r8dv5q" path="res://resources/data/cards/card.gd" id="1_uvxrb"]
|
||||
[ext_resource type="Script" uid="uid://d2vr5ocvib663" path="res://resources/data/boosters/booster.gd" id="2_1ex0h"]
|
||||
[ext_resource type="Resource" uid="uid://bsto1qwayy1sk" path="res://resources/data/cards/water_slime.tres" id="2_hsyr7"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_1ex0h")
|
||||
name = "Base Booster"
|
||||
counts = {
|
||||
"Common": 4,
|
||||
"Rare": 1
|
||||
}
|
||||
cards = Array[ExtResource("1_uvxrb")]([ExtResource("2_hsyr7")])
|
||||
metadata/_custom_type_script = "uid://d2vr5ocvib663"
|
7
resources/data/cards/card.gd
Normal file
7
resources/data/cards/card.gd
Normal file
@@ -0,0 +1,7 @@
|
||||
extends Resource
|
||||
class_name Card
|
||||
|
||||
@export var name: String
|
||||
@export var hp: int
|
||||
@export var damage: int
|
||||
@export var rarity: String = "Common"
|
1
resources/data/cards/card.gd.uid
Normal file
1
resources/data/cards/card.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://5pqr71r8dv5q
|
11
resources/data/cards/king_slime.tres
Normal file
11
resources/data/cards/king_slime.tres
Normal file
@@ -0,0 +1,11 @@
|
||||
[gd_resource type="Resource" script_class="Card" load_steps=2 format=3 uid="uid://r20ullywveey"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://5pqr71r8dv5q" path="res://resources/data/cards/card.gd" id="1_w886e"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_w886e")
|
||||
name = "Water Slime"
|
||||
hp = 80
|
||||
damage = 40
|
||||
rarity = "Rare"
|
||||
metadata/_custom_type_script = "uid://5pqr71r8dv5q"
|
10
resources/data/cards/water_slime.tres
Normal file
10
resources/data/cards/water_slime.tres
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_resource type="Resource" script_class="Card" load_steps=2 format=3 uid="uid://bsto1qwayy1sk"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://5pqr71r8dv5q" path="res://resources/data/cards/card.gd" id="1_rk1da"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_rk1da")
|
||||
name = "Water Slime"
|
||||
hp = 40
|
||||
damage = 10
|
||||
metadata/_custom_type_script = "uid://5pqr71r8dv5q"
|
35
scenes/entrypoint.tscn
Normal file
35
scenes/entrypoint.tscn
Normal file
@@ -0,0 +1,35 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://c37m0t4dwnwbn"]
|
||||
|
||||
[ext_resource type="Resource" uid="uid://c63rkr0cudnom" path="res://resources/data/boosters/new_base_booster.tres" id="1_ki0t7"]
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_0ug6y"]
|
||||
script/source = "extends Node2D
|
||||
|
||||
|
||||
@export var booster: Booster
|
||||
|
||||
func _ready() -> void:
|
||||
print(booster.draw())
|
||||
"
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_yqgyj"]
|
||||
script/source = "extends Label
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
text = str(GameState.data.money)
|
||||
GameState.add_money(1000)
|
||||
"
|
||||
|
||||
[node name="Entrypoint" type="Node2D"]
|
||||
script = SubResource("GDScript_0ug6y")
|
||||
booster = ExtResource("1_ki0t7")
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_left = 504.0
|
||||
offset_top = 255.0
|
||||
offset_right = 544.0
|
||||
offset_bottom = 278.0
|
||||
script = SubResource("GDScript_yqgyj")
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
position = Vector2(577, 325)
|
41
scripts/autoload/game_state.gd
Normal file
41
scripts/autoload/game_state.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
extends Node
|
||||
|
||||
signal money_changed(new_money)
|
||||
|
||||
var _save_dir := "user://saves"
|
||||
|
||||
var data := {
|
||||
"money": 1000,
|
||||
"day": 1
|
||||
}
|
||||
|
||||
func list_saves():
|
||||
var dir := DirAccess.open("user://saves")
|
||||
var saves = dir.get_files()
|
||||
var res: Array[Save] = []
|
||||
for save in saves:
|
||||
res.append(Save.new())
|
||||
func add_money(amount):
|
||||
data.money += amount
|
||||
emit_signal("money_changed", data.money)
|
||||
|
||||
var save_path = "user://save.bin"
|
||||
|
||||
func save_save():
|
||||
var file = FileAccess.open(save_path, FileAccess.WRITE)
|
||||
file.store_buffer(JSONPacker.encode(data))
|
||||
|
||||
func load_save(path: String):
|
||||
if FileAccess.file_exists(path):
|
||||
var file = FileAccess.open(path, FileAccess.READ)
|
||||
data = JSONPacker.decode(file.get_buffer(file.get_length()))
|
||||
return true
|
||||
return false
|
||||
|
||||
func _init() -> void:
|
||||
load_state()
|
||||
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_WM_CLOSE_REQUEST:
|
||||
save_state()
|
||||
get_tree().quit() # default behavior
|
1
scripts/autoload/game_state.gd.uid
Normal file
1
scripts/autoload/game_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://nkr0vilsuhfk
|
5
scripts/interfaces/save.gd
Normal file
5
scripts/interfaces/save.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Resource
|
||||
class_name Save
|
||||
|
||||
@export var money: int
|
||||
@export var day: int
|
1
scripts/interfaces/save.gd.uid
Normal file
1
scripts/interfaces/save.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b7g047l14kcxh
|
264
scripts/utils/json_packer.gd
Normal file
264
scripts/utils/json_packer.gd
Normal file
@@ -0,0 +1,264 @@
|
||||
class_name JSONPacker
|
||||
|
||||
enum Type {
|
||||
NUM = 0x00,
|
||||
LIT = 0x40,
|
||||
ARR = 0x80,
|
||||
BOL = 0xA0,
|
||||
OBJ = 0xC0,
|
||||
STR = 0xE0,
|
||||
MULTI = 0x10,
|
||||
INT = 0x00,
|
||||
FLOAT = 0x04,
|
||||
L8 = 0x00,
|
||||
L16 = 0x01,
|
||||
L32 = 0x02,
|
||||
L64 = 0x03,
|
||||
NULL = 0x00,
|
||||
UNDEFINED = 0x01,
|
||||
NAN = 0x02
|
||||
}
|
||||
|
||||
|
||||
static func encode(value) -> PackedByteArray:
|
||||
if typeof(value) == TYPE_NIL:
|
||||
#print("packing NIL")
|
||||
return PackedByteArray([Type.LIT | Type.NULL])
|
||||
elif typeof(value) == TYPE_BOOL:
|
||||
#print("packing bool")
|
||||
return PackedByteArray([Type.BOL | (1 if value else 0)])
|
||||
elif typeof(value) == TYPE_INT or typeof(value) == TYPE_FLOAT:
|
||||
#print("packing int")
|
||||
if typeof(value) == TYPE_FLOAT and is_nan(value):
|
||||
#print("packing float")
|
||||
return PackedByteArray([Type.LIT | Type.NAN])
|
||||
var encoded = _encode_number(value)
|
||||
if encoded.type == 0:
|
||||
return encoded.data
|
||||
return _concat([PackedByteArray([Type.NUM | encoded.type]), encoded.data])
|
||||
elif typeof(value) == TYPE_STRING:
|
||||
#print("packing string")
|
||||
var utf8 = value.to_utf8_buffer()
|
||||
var length = utf8.size()
|
||||
if length > 0x0F:
|
||||
var encoded = _encode_number(length)
|
||||
return _concat([PackedByteArray([Type.STR | encoded.type]), encoded.data, utf8])
|
||||
return _concat([PackedByteArray([Type.STR | length]), utf8])
|
||||
elif typeof(value) == TYPE_ARRAY:
|
||||
#print("packing array")
|
||||
var length = value.size()
|
||||
var items = []
|
||||
if length > 0x0F:
|
||||
var encoded = _encode_number(length)
|
||||
items.append(PackedByteArray([Type.ARR | encoded.type]))
|
||||
items.append(encoded.data)
|
||||
else:
|
||||
items.append(PackedByteArray([Type.ARR | length]))
|
||||
for v in value:
|
||||
items.append(encode(v))
|
||||
|
||||
return _concat(items)
|
||||
elif typeof(value) == TYPE_DICTIONARY:
|
||||
#print("packing object")
|
||||
var keys = value.keys()
|
||||
var items = []
|
||||
if keys.size() > 0x0F:
|
||||
var encoded = _encode_number(keys.size())
|
||||
items.append(PackedByteArray([Type.OBJ | encoded.type]))
|
||||
items.append(encoded.bfr)
|
||||
else:
|
||||
items.append(PackedByteArray([Type.OBJ | keys.size()]))
|
||||
for key in keys:
|
||||
items.append(encode(str(key)))
|
||||
items.append(encode(value[key]))
|
||||
return _concat(items)
|
||||
else:
|
||||
push_error("Unsupported type: " + str(typeof(value)))
|
||||
return PackedByteArray()
|
||||
|
||||
static func _encode_number(value):
|
||||
var isInt = typeof(value) == TYPE_INT
|
||||
#print("compiling value")
|
||||
#print(value)
|
||||
if isInt and value >= 0 and value <= 0x0F:
|
||||
#print("int between 0x0 & 0x0F")
|
||||
return { "type": 0, "data": PackedByteArray([value]) }
|
||||
|
||||
elif isInt and value >= -0x7F and value <= 0x7F:
|
||||
#print("int between -07F & 0x7F")
|
||||
return {
|
||||
"type": Type.MULTI | Type.INT | Type.L8,
|
||||
"data": PackedByteArray([value])
|
||||
}
|
||||
|
||||
elif isInt and value >= -0x7FFF and value <= 0x7FFF:
|
||||
#print("int between -07FFF & 0x7FFF")
|
||||
var bfr = PackedByteArray()
|
||||
bfr.resize(2)
|
||||
bfr.encode_s16(0, value)
|
||||
return {
|
||||
"type": Type.MULTI | Type.INT | Type.L16,
|
||||
"data": bfr
|
||||
}
|
||||
|
||||
elif isInt:
|
||||
#print("int for other cases")
|
||||
var bfr = PackedByteArray()
|
||||
bfr.resize(4)
|
||||
bfr.encode_s32(0, value)
|
||||
return {
|
||||
"type": Type.MULTI | Type.INT | Type.L32,
|
||||
"data": bfr
|
||||
}
|
||||
|
||||
elif typeof(value) == TYPE_FLOAT:
|
||||
#print("float")
|
||||
var bfr = PackedByteArray()
|
||||
bfr.resize(8)
|
||||
bfr.encode_double(0, value)
|
||||
return {
|
||||
"type": Type.MULTI | Type.FLOAT | Type.L64,
|
||||
"data": bfr
|
||||
}
|
||||
|
||||
push_error("Unsupported number type")
|
||||
return { "type": 0, "data": PackedByteArray() }
|
||||
|
||||
static func _concat(args: Array) -> PackedByteArray:
|
||||
print("concat", args)
|
||||
var result = PackedByteArray()
|
||||
for arr in args:
|
||||
print("res", arr)
|
||||
result.append_array(arr)
|
||||
return result
|
||||
|
||||
static func decode(bfr: PackedByteArray) -> Variant:
|
||||
return decode_with_end(bfr)["value"]
|
||||
|
||||
static func decode_with_end(bfr: PackedByteArray) -> Dictionary:
|
||||
var firstByte = bfr[0]
|
||||
var type = firstByte & 0xE0
|
||||
var isMulti = firstByte & 0x10
|
||||
|
||||
if type == Type.LIT:
|
||||
var subtype = firstByte & 0x0F
|
||||
match subtype:
|
||||
Type.NULL:
|
||||
return {"value": null, "end": 1}
|
||||
Type.UNDEFINED:
|
||||
return {"value": null, "end": 1}
|
||||
Type.NAN:
|
||||
return {"value": float('nan'), "end": 1}
|
||||
|
||||
if (firstByte & 0xC0) == 0 && !isMulti:
|
||||
return {"value": firstByte, "end": 1}
|
||||
elif (firstByte & 0xC0) == 0 && isMulti:
|
||||
return _decode_number(firstByte, bfr)
|
||||
|
||||
match type:
|
||||
Type.STR:
|
||||
if !isMulti:
|
||||
var len = firstByte & 0x0F
|
||||
return { "value": bfr.slice(1, len + 1).get_string_from_utf8(), "end": len + 1}
|
||||
else:
|
||||
var tmp = _decode_number(firstByte, bfr)
|
||||
var len = tmp.value
|
||||
var lenlen = tmp.end
|
||||
return { "value": bfr.slice(lenlen, lenlen + len).get_string_from_utf8(), "end": lenlen + len}
|
||||
Type.BOL:
|
||||
return {"value": bool(firstByte), "end": 1}
|
||||
Type.ARR:
|
||||
if !isMulti:
|
||||
var len = firstByte & 0x0F
|
||||
var offset = 1
|
||||
var list = []
|
||||
for i in len:
|
||||
var tmp = decode_with_end(bfr.slice(offset))
|
||||
var value = tmp.value
|
||||
var newOffset = tmp.end
|
||||
list.append(value)
|
||||
offset += newOffset
|
||||
return {"value": list, "end": offset}
|
||||
else:
|
||||
var tmp1 = _decode_number(firstByte, bfr)
|
||||
var len = tmp1.value
|
||||
var lenlen = tmp1.end
|
||||
var offset = lenlen
|
||||
var list = []
|
||||
for i in len:
|
||||
var tmp = decode_with_end(bfr.slice(offset))
|
||||
var value = tmp.value
|
||||
var newOffset = tmp.end
|
||||
list.append(value)
|
||||
offset += newOffset
|
||||
return {"value": list, "end": offset}
|
||||
Type.OBJ:
|
||||
var dict := {}
|
||||
if !isMulti:
|
||||
var len = firstByte & 0x0F
|
||||
var offset = 1
|
||||
for i in len:
|
||||
var tmpA = decode_with_end(bfr.slice(offset))
|
||||
var key = tmpA.value
|
||||
var tmpOffset = tmpA.end
|
||||
var tmpB = decode_with_end(bfr.slice(offset + tmpOffset))
|
||||
var value = tmpB.value
|
||||
var newOffset = tmpB.end
|
||||
dict[key] = value
|
||||
offset += tmpOffset + newOffset
|
||||
return {"value": dict, "end": offset}
|
||||
else:
|
||||
var tmp = _decode_number(firstByte, bfr)
|
||||
var len = tmp.value
|
||||
var lenlen = tmp.end
|
||||
var offset = lenlen
|
||||
for i in len:
|
||||
var tmpA = decode_with_end(bfr.slice(offset))
|
||||
var key = tmpA.value
|
||||
var tmpOffset = tmpA.end
|
||||
var tmpB = decode_with_end(bfr.slice(offset + tmpOffset))
|
||||
var value = tmpB.value
|
||||
var newOffset = tmpB.end
|
||||
dict[key] = value
|
||||
offset += tmpOffset + newOffset
|
||||
return {"value": dict, "end": offset}
|
||||
_:
|
||||
push_error("Unknown type: " + str(type))
|
||||
return {"value": null, "end": 0}
|
||||
return {"value": null, "end": 0}
|
||||
|
||||
static func _decode_float(bfr: PackedByteArray, offset: int = 0, bigEndian = false) -> float:
|
||||
if bigEndian:
|
||||
return bfr.decode_float(offset)
|
||||
return PackedByteArray([bfr[offset+3], bfr[offset+2], bfr[offset+1], bfr[offset+0]]).decode_float(0)
|
||||
|
||||
static func _decode_number(type: int, bfr: PackedByteArray) -> Dictionary:
|
||||
var subtype := type & 0x0C
|
||||
var len := type & 0x03
|
||||
var bytes := 1
|
||||
var value
|
||||
match subtype:
|
||||
Type.FLOAT:
|
||||
if len == Type.L32:
|
||||
#print(bfr.slice(1, 5))
|
||||
value = _decode_float(bfr, 1)
|
||||
#print(value)
|
||||
bytes = 4
|
||||
elif len == Type.L64:
|
||||
value = bfr.decode_double(1)
|
||||
bytes = 8
|
||||
Type.INT:
|
||||
if len == Type.L8:
|
||||
value = bfr.decode_s8(1)
|
||||
elif len == Type.L16:
|
||||
value = bfr.decode_s16(1)
|
||||
bytes = 2
|
||||
elif len == Type.L32:
|
||||
value = bfr.decode_s32(1)
|
||||
bytes = 4
|
||||
#if value < 0:
|
||||
#print("possible underflow")
|
||||
#print(subtype)
|
||||
#print(len)
|
||||
#print(value)
|
||||
return {"value": value, "end": bytes + 1}
|
1
scripts/utils/json_packer.gd.uid
Normal file
1
scripts/utils/json_packer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bxr48ok8lsqt0
|
Reference in New Issue
Block a user