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