-
Notifications
You must be signed in to change notification settings - Fork 247
Adds a per-level persistence system. #5176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MistakeNot4892
wants to merge
1
commit into
NebulaSS13:dev
Choose a base branch
from
MistakeNot4892:feature/limited_persistence
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // Handled elsewhere, do not let them load like vars. | ||
| var/global/list/_forbid_field_load = list( | ||
| (nameof(/datum::type)) = TRUE, | ||
| (nameof(/atom::loc)) = TRUE | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| #define SERDE_HINT_FINISHED 1 | ||
| #define SERDE_HINT_POSTINIT 2 | ||
|
|
||
| #define SERDE_REAGENT_LIST "_reagent_list" | ||
| #define SERDE_REAGENT_VOLUME "_reagent_volume" | ||
|
|
||
| #define SERIALIZE_VALUE(V, T, VAL) .[nameof(T::V)] = VAL; | ||
| #define SERIALIZE(V, T) SERIALIZE_VALUE(V, T, V) | ||
| #define SERIALIZE_IF_MODIFIED(V, T) if(V != initial(V)) { SERIALIZE_VALUE(V, T, V) } | ||
| #define SERIALIZE_TYPE_IF_MODIFIED(V, T) if(V != initial(V)) { SERIALIZE_VALUE(V, T, "[V]") } | ||
| #define SERIALIZE_DECL_IF_MODIFIED(V, T) if((isnull(V) && !isnull(initial(V))) || ((istext(V) || istype(V, /decl) || ispath(V, /decl)) && !DECLS_ARE_EQUIVALENT(V, initial(V)))) { var/decl/__D = RESOLVE_TO_DECL(V); SERIALIZE_VALUE(V, T, __D?.uid) } | ||
| #define SERIALIZE_DECL_LIST(V, T) if(islist(V)) { var/list/__decl_uids = list(); for(var/decl/__decl in V) { __decl_uids += __decl.uid }; SERIALIZE_VALUE(V, T, __decl_uids) } | ||
| #define SERIALIZE_REAGENTS(V, T, I) if(istype(V, /datum/reagents)) { \ | ||
| .[I + SERDE_REAGENT_VOLUME] = UNLINT(V.maximum_volume); \ | ||
| if(UNLINT(V.total_volume)) { \ | ||
| var/list/__compiled_reagents = list(); \ | ||
| for(var/decl/material/R in UNLINT(V.liquid_volumes)) { \ | ||
| __compiled_reagents[++__compiled_reagents.len] = list(R.uid, UNLINT(V.liquid_volumes[R]), (MAT_PHASE_LIQUID)); \ | ||
| } \ | ||
| for(var/decl/material/R in UNLINT(V.solid_volumes)) { \ | ||
| __compiled_reagents[++__compiled_reagents.len] = list(R.uid, UNLINT(V.solid_volumes[R]), (MAT_PHASE_SOLID)); \ | ||
| } \ | ||
| .[I + SERDE_REAGENT_LIST] = __compiled_reagents; \ | ||
| } else { \ | ||
| .[I + SERDE_REAGENT_LIST] = list(); \ | ||
| } \ | ||
| } else { \ | ||
| .[I + SERDE_REAGENT_LIST] = list(); \ | ||
| .[I + SERDE_REAGENT_VOLUME] = 0; \ | ||
| } | ||
|
|
||
| #define DESERIALIZE_REAGENTS(V, I) if(((I + SERDE_REAGENT_LIST) in __deserialization_payload) && ((I + SERDE_REAGENT_VOLUME) in __deserialization_payload)) { \ | ||
| V = list((SERDE_REAGENT_VOLUME) = __deserialization_payload[I + SERDE_REAGENT_VOLUME], (SERDE_REAGENT_LIST) = __deserialization_payload[I + SERDE_REAGENT_LIST]); \ | ||
| } | ||
|
|
||
| #define DESERIALIZE_DECL_TO_TYPE(V) if(istext(V) || ispath(V, /decl) || istype(V, /decl)) { var/decl/__D = RESOLVE_TO_DECL(V); V = __D?.type; } else { V = null; } | ||
| #define DESERIALIZE_TYPE(V) if(istext(V)) { V = text2path(V); } else if(!ispath(V)) { V = null; } | ||
| #define DESERIALIZE_DECL(V) if(istext(V) || ispath(V)) { V = RESOLVE_TO_DECL(V); } else { V = null; } | ||
|
|
||
| // List cast is to avoid OpenDream complaining about V typically being typed as a reagents datum, but holding a list for serde. | ||
| #define FINALIZE_REAGENTS_SERDE_BODY(V) try { \ | ||
| if((SERDE_REAGENT_LIST in V) && (SERDE_REAGENT_VOLUME in V)) { \ | ||
| var/list/LV = V; \ | ||
| var/__serde_volume = LV[SERDE_REAGENT_VOLUME]; \ | ||
| if(__serde_volume <= 0) { \ | ||
| V = null; \ | ||
| } else { \ | ||
| var/list/__serde_reagents = LV[SERDE_REAGENT_LIST]; \ | ||
| V = new /datum/reagents(__serde_volume, src); \ | ||
| for(var/list/entry in __serde_reagents) { \ | ||
| V.add_reagent(RESOLVE_TO_DECL(entry[1]), entry[2], phase = entry[3], defer_update = TRUE); \ | ||
| } \ | ||
| V.handle_update(); \ | ||
| } \ | ||
| } else { \ | ||
| V = null; \ | ||
| } \ | ||
| } catch(var/exception/E) { \ | ||
| log_error("Exception while finalizing reagents load for [type]: [EXCEPTION_TEXT(E)]"); \ | ||
| V = null; \ | ||
| } | ||
|
|
||
| #define FINALIZE_REAGENTS_SERDE(V) if(islist(V)) { FINALIZE_REAGENTS_SERDE_BODY(V); } | ||
| #define FINALIZE_REAGENTS_SERDE_AND_RETURN(V) if(islist(V)) { FINALIZE_REAGENTS_SERDE_BODY(V); return; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| /proc/instantiate_serialized_data(load_z, requestor, list/instance_map, entries_decay_at, entry_decay_weight) | ||
|
|
||
| var/list/nested_instances = list() | ||
| var/list/instanced_areas = list() | ||
| var/list/created_data = list() | ||
|
|
||
| LAZYINITLIST(instance_map) | ||
|
|
||
| to_world_log("Finalising load of [length(instance_map)] instance\s for level '[requestor]'.") | ||
| for(var/uid in instance_map) | ||
|
|
||
| var/list/instance_data = instance_map[uid] | ||
| try | ||
|
|
||
| var/raw_load_path = instance_data[nameof(/datum::type)] | ||
| var/load_path = ispath(raw_load_path, /datum) ? raw_load_path : text2path(raw_load_path) | ||
| if(!ispath(load_path, /datum)) | ||
| error("[requestor]: attempted to load persistent instance with invalid or non-/datum type '[raw_load_path]'") | ||
| continue | ||
|
|
||
| var/datum/created_instance | ||
|
|
||
| // Instance is a /datum. | ||
| // Just pass the data in and assume the datum type knows what to do with it. | ||
| if(!ispath(load_path, /atom) && ispath(load_path, /datum)) | ||
| created_instance = new load_path(instance_data) | ||
| created_data += created_instance | ||
| else | ||
| var/list/spawn_data = instance_data[nameof(/atom/movable::loc)] | ||
| if(spawn_data) | ||
|
|
||
| if(isnull(spawn_data) || length(spawn_data) < 3) | ||
| error("[requestor]: attempted to load persistent instance with malformed loc.") | ||
| continue | ||
|
|
||
| // Instance has a world coordinate. | ||
| if(islist(spawn_data)) | ||
| var/turf/spawn_loc = locate(spawn_data[1], spawn_data[2], isnull(load_z) ? spawn_data[3] : load_z) | ||
| if(!istype(spawn_loc)) | ||
| error("[requestor]: attempted to load persistent instance but could not find spawn loc.") | ||
| continue | ||
| if(ispath(load_path, /turf)) | ||
| if(spawn_loc.type == load_path) | ||
| created_instance = spawn_loc | ||
| else | ||
| created_instance = spawn_loc.ChangeTurf(load_path) | ||
|
|
||
| // TODO: Areas will need bespoke handling for non-subtype-related persistence (blueprint renaming etc). | ||
| else if(ispath(load_path, /area)) | ||
| var/area/area = instanced_areas[load_path] | ||
| if(!area) | ||
| area = new load_path(null) | ||
| instanced_areas[load_path] = area | ||
| ChangeArea(spawn_loc, area) | ||
|
|
||
| else if(ispath(load_path, /atom)) | ||
| created_instance = new load_path(spawn_loc) | ||
| spawn_loc._contents_were_modified = TRUE // ensure | ||
| else | ||
| error("[requestor]: attempted to instantiate unimplemented path '[load_path]'.") | ||
| continue | ||
|
|
||
| // Instance is inside another instance; implies/requires /atom/movable | ||
| else if(istext(spawn_data)) | ||
| if(!ispath(load_path, /atom/movable)) | ||
| error("[requestor]: tried to spawn non-movable [load_path] inside an instance.") | ||
| continue | ||
| created_instance = new load_path | ||
| nested_instances[created_instance] = spawn_data | ||
|
|
||
| else | ||
| error("[requestor]: attempted to load persistent instance with malformed loc.") | ||
| continue | ||
|
|
||
| else | ||
| // Should we just go ahead and do this to create atoms in nullspace? | ||
| // Would we ever want to track an atom in nullspace via level persistence? | ||
| error("[requestor]: attempted to load non-/datum persistent instance with no spawn loc.") | ||
|
|
||
| if(istype(created_instance)) | ||
| LAZYSET(., uid, created_instance) | ||
| if(isatom(created_instance)) | ||
| var/atom/atom = created_instance | ||
| atom.__deserialization_payload = instance_data | ||
| SSatoms.deserialized_atoms[uid] = atom | ||
| if(!isnull(entries_decay_at) && !isnull(entry_decay_weight)) | ||
| created_instance.HandlePersistentDecay(entries_decay_at, entry_decay_weight) | ||
|
|
||
| catch(var/exception/E) | ||
| log_error("Exception during persistent instance load - [islist(instance_data) ? json_encode(instance_data) : "no instance data"]: [EXCEPTION_TEXT(E)]") | ||
|
|
||
| // Atoms use SSatoms for this, datums don't go through SSatoms so need to do it here. | ||
| for(var/datum/instance in created_data) | ||
| instance.DeserializePostInit(.) | ||
|
|
||
| // Resolve any loc references to instances. | ||
| for(var/atom/movable/atom as anything in nested_instances) | ||
| var/nested_atom_id = nested_instances[atom] | ||
| var/atom/nested_atom = .[nested_atom_id] | ||
| if(!istype(nested_atom)) | ||
| error("[requestor]: could not resolve instance ref [nested_atom_id] to instance.") | ||
| continue | ||
| atom.forceMove(nested_atom) | ||
| nested_atom.contents_were_modified() | ||
|
|
||
| // Now that everything is loaded and placed, clear out anything that should not be present on the turfs we've loaded. | ||
| for(var/uid in SSatoms.deserialized_atoms) | ||
| var/turf/turf = SSatoms.deserialized_atoms[uid] | ||
| if(!istype(turf)) | ||
| continue | ||
| for(var/atom/thing in turf) | ||
| if(!thing.simulated) | ||
| continue | ||
| if(!isnull(thing.__deserialization_payload)) | ||
| continue | ||
| qdel(thing) | ||
|
|
||
| to_world_log("[requestor] loaded [length(.)] persistent instance\s.") | ||
|
|
||
| /proc/apply_serde_message_decay(_message, _age, _decay_weight, _decay_at) | ||
| var/static/list/decayed_chars = list(".",",","-","'","\\","/","\"",":",";") | ||
| if(_age < _decay_at || isnull(_message)) | ||
| return _message | ||
| . = "" | ||
| for(var/i = 1 to length(_message)) | ||
| var/char = copytext(_message, i, i + 1) | ||
| if(prob(round(_age * _decay_weight))) | ||
| if(prob(99)) | ||
| . += pick(decayed_chars) | ||
| else | ||
| . += char |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.