@tool class_name SaveGame extends Resource var _is_initialised: bool = false @export var filepath: String: set(value): filepath = value if _is_initialised: read_save_file() changed.emit() @export var unique_save_name: String = "frame_of_mind_%s_%s" % [Time.get_date_string_from_system(), Time.get_time_string_from_system().replace(":", "-")]: set(value): unique_save_name = value if _is_initialised: changed.emit() @export var current_room: State.rooms = State.rooms.NULL: set(value): current_room = value if _is_initialised: changed.emit() @export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0: set(value): mementos_complete = value if _is_initialised: changed.emit() @export var board_state: Dictionary = {"cards": {}, "stickies": {}, "randoms": []}: set(value): board_state = value if _is_initialised: changed.emit() @export var is_childhood_board_complete: bool = false @export var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png"): set(value): thumbnail = value if _is_initialised: changed.emit() @export var last_saved: int = int(Time.get_unix_time_from_system()): set(value): last_saved = value if _is_initialised: changed.emit() @export var is_valid: bool = false @export var is_demo: bool = OS.has_feature("Demo") @export var is_empty: bool = true: get(): return not FileAccess.file_exists("%s.json:" % filepath) @export var save_manually: bool = false: set(val): if val: save_to_file(thumbnail) func _validate_property(property: Dictionary): if property.name == filepath: property.usage |= PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED if property.name == "thumbnail": property.usage |= PROPERTY_USAGE_READ_ONLY if property.name == "is_valid": property.usage |= PROPERTY_USAGE_READ_ONLY if property.name == "is_empty": property.usage |= PROPERTY_USAGE_READ_ONLY func _init(initial_filepath = "") -> void: if initial_filepath == "": filepath = "%s/%s.json" % [State.user_saves_path, unique_save_name] else: filepath = initial_filepath unique_save_name = initial_filepath.get_file() read_save_file() _is_initialised = true if not DirAccess.dir_exists_absolute(filepath.get_base_dir()): DirAccess.make_dir_absolute(filepath.get_base_dir()) func read_save_file(): print("Opening Savegame: %s" % filepath) if FileAccess.file_exists(filepath): var file = FileAccess.open(filepath, FileAccess.READ) var raw_json = FileAccess.get_file_as_string(filepath) file.close() var parsed: Dictionary = JSON.parse_string(raw_json) var tmp_img: Image if FileAccess.file_exists("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]): tmp_img = Image.load_from_file("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]) var are_types_valid = ( parsed["unique_save_name"] is String and parsed["current_room"] is float and parsed["mementos_complete"] is float and parsed["board_state"] is Dictionary and parsed["is_childhood_board_complete"] is bool and parsed["last_saved"] is float and parsed["demo"] is bool and last_saved != 0 ) if are_types_valid: for key in parsed.keys(): set(key, parsed[key]) for dict:Dictionary in board_state.values(): for key in dict.keys(): if dict[key] is String: if dict[key].begins_with("("): dict[key] = parse_vec_from_string(dict[key]) var cards: Dictionary[StringName, Variant] var stickies: Dictionary[StringName, Variant] var randoms: Array[StringName] for cardname:String in board_state["cards"]: cards[StringName(cardname)] = board_state["cards"][cardname] for sticky_name:String in board_state["stickies"]: stickies[StringName(sticky_name)] = board_state["stickies"][sticky_name] for random_name:StringName in board_state["randoms"]: randoms.append( board_state["randoms"][random_name] ) board_state = { "cards": cards, "stickies": stickies, "randoms": randoms } is_valid = are_types_valid \ and current_room >= 0 \ and current_room < State.rooms.keys().size() \ and validate_board_state() if not is_valid: push_error("Parsing of Save failed.") if tmp_img != null: thumbnail = ImageTexture.create_from_image(tmp_img) is_empty = false else: is_valid = true func _get_save_dict() -> Dictionary: return { "unique_save_name": unique_save_name, "current_room": current_room, "mementos_complete": mementos_complete, "board_state": board_state, "is_childhood_board_complete": is_childhood_board_complete, "last_saved": last_saved, "is_demo": is_demo } func save_to_file(current_screen: Texture): last_saved = Time.get_unix_time_from_system() var thumbnail_image: Image = current_screen.get_image() thumbnail_image.convert(Image.Format.FORMAT_RGB8) thumbnail_image.linear_to_srgb() thumbnail_image.resize(384, 261, Image.INTERPOLATE_LANCZOS) # nonexistent call in ViewportTexturew var thumbnail_path: String = "%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name] var save_dir = DirAccess.open(filepath.get_base_dir()) if not save_dir.dir_exists("thumbnails"): save_dir.make_dir("thumbnails") thumbnail_image.save_png("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]) #thumbnail_image.save_png("%s/test.png" % State.user_saves_path) print(filepath.get_base_dir()) var file = FileAccess.open(filepath, FileAccess.WRITE) file.store_string(JSON.stringify(_get_save_dict())) file.close() func calculate_completed_sequences() -> int: var i: int = mementos_complete - ((mementos_complete >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); i = (i + (i >> 4)) & 0x0F0F0F0F; i *= 0x01010101; return i >> 24; func calculate_total_connections() -> int: var connections:= 0 for sticky_position in board_state.stickies.values(): connections += int(sticky_position is String) return connections func validate_board_state() -> bool: if board_state.keys().has("cards") and board_state.keys().has("stickies"): for card in board_state.cards.values(): if not card is Vector2: push_error("Save %s could not be parsed: Corrupted Cards." % unique_save_name) return false for sticky in board_state.stickies.values(): if not (sticky == -1 or sticky is Vector2 or board_state.cards.keys.has(sticky)): push_error("Save %s could not be parsed: Corrupted Sticky Notes.") return false return true return false func parse_vec_from_string(string: String) -> Vector2: var string_array = string.replace("(", "").replace(")", "").split(", ") return Vector2(float(string_array[0]), float(string_array[1]))