init
This commit is contained in:
commit
b99855351d
434 changed files with 50357 additions and 0 deletions
373
addons/inkgd/runtime/variables_state.gd
Normal file
373
addons/inkgd/runtime/variables_state.gd
Normal file
|
@ -0,0 +1,373 @@
|
|||
# warning-ignore-all:shadowed_variable
|
||||
# warning-ignore-all:unused_class_variable
|
||||
# warning-ignore-all:return_value_discarded
|
||||
# ############################################################################ #
|
||||
# Copyright © 2015-2021 inkle Ltd.
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This file is part of inkgd.
|
||||
# inkgd is licensed under the terms of the MIT license.
|
||||
# ############################################################################ #
|
||||
|
||||
extends InkBase
|
||||
|
||||
class_name InkVariablesState
|
||||
|
||||
# ############################################################################ #
|
||||
# Imports
|
||||
# ############################################################################ #
|
||||
|
||||
var InkTryGetResult := preload("res://addons/inkgd/runtime/extra/try_get_result.gd") as GDScript
|
||||
var InkStringSet := preload("res://addons/inkgd/runtime/extra/string_set.gd") as GDScript
|
||||
|
||||
var InkValue := load("res://addons/inkgd/runtime/values/value.gd") as GDScript
|
||||
var InkListValue := load("res://addons/inkgd/runtime/values/list_value.gd") as GDScript
|
||||
var InkVariablePointerValue := load("res://addons/inkgd/runtime/values/variable_pointer_value.gd") as GDScript
|
||||
|
||||
# ############################################################################ #
|
||||
|
||||
# (String, InkObject)
|
||||
signal variable_changed(variable_name, new_value)
|
||||
|
||||
# ############################################################################ #
|
||||
|
||||
var patch: InkStatePatch # StatePatch
|
||||
|
||||
var batch_observing_variable_changes: bool:
|
||||
get:
|
||||
return _batch_observing_variable_changes
|
||||
|
||||
set(value):
|
||||
_batch_observing_variable_changes = value
|
||||
if value:
|
||||
_changed_variables_for_batch_obs = InkStringSet.new()
|
||||
else:
|
||||
if _changed_variables_for_batch_obs != null:
|
||||
for variable_name in _changed_variables_for_batch_obs.enumerate():
|
||||
var current_value = _global_variables[variable_name]
|
||||
emit_signal("variable_changed", variable_name, current_value)
|
||||
|
||||
_changed_variables_for_batch_obs = null
|
||||
|
||||
var _batch_observing_variable_changes: bool = false
|
||||
|
||||
var callstack: InkCallStack: get = get_callstack, set = set_callstack
|
||||
func get_callstack() -> InkCallStack:
|
||||
return _callstack
|
||||
|
||||
func set_callstack(value: InkCallStack):
|
||||
_callstack = value
|
||||
|
||||
# (String) -> Variant
|
||||
func get_variable(variable_name: String):
|
||||
if self.patch != null:
|
||||
var global: InkTryGetResult = patch.try_get_global(variable_name)
|
||||
if global.exists:
|
||||
return global.result.value_object
|
||||
|
||||
if _global_variables.has(variable_name):
|
||||
return _global_variables[variable_name].value_object
|
||||
elif _default_global_variables.has(variable_name):
|
||||
return _default_global_variables[variable_name].value_object
|
||||
else:
|
||||
return null
|
||||
|
||||
# (String, Variant) -> void
|
||||
func set_variable(variable_name: String, value) -> void:
|
||||
if !_default_global_variables.has(variable_name):
|
||||
InkUtils.throw_story_exception(
|
||||
"Cannot assign to a variable (%s) that hasn't been declared in the story" \
|
||||
% variable_name
|
||||
)
|
||||
return
|
||||
|
||||
var val: InkValue = InkValue.create(value)
|
||||
if val == null:
|
||||
if value == null:
|
||||
InkUtils.throw_exception("Cannot pass null to VariableState")
|
||||
else:
|
||||
InkUtils.throw_exception("Invalid value passed to VariableState: %s" % str(value))
|
||||
return
|
||||
|
||||
set_global(variable_name, val)
|
||||
|
||||
func enumerate() -> Array:
|
||||
return _global_variables.keys()
|
||||
|
||||
func _init(callstack: InkCallStack, list_defs_origin: InkListDefinitionsOrigin, ink_runtime = null):
|
||||
find_static_objects(ink_runtime)
|
||||
|
||||
_global_variables = {}
|
||||
_callstack = callstack
|
||||
_list_defs_origin = list_defs_origin
|
||||
|
||||
# () -> void
|
||||
func apply_patch() -> void:
|
||||
for named_var_key in self.patch.globals:
|
||||
_global_variables[named_var_key] = self.patch.globals[named_var_key]
|
||||
|
||||
if _changed_variables_for_batch_obs != null:
|
||||
for name in self.patch.changed_variables.enumerate():
|
||||
_changed_variables_for_batch_obs.append(name)
|
||||
|
||||
patch = null
|
||||
|
||||
# (Dictionary<string, Variant>) -> void
|
||||
func set_json_token(jtoken: Dictionary) -> void:
|
||||
_global_variables.clear()
|
||||
|
||||
for var_val_key in _default_global_variables:
|
||||
if jtoken.has(var_val_key):
|
||||
var loaded_token = jtoken[var_val_key]
|
||||
_global_variables[var_val_key] = self.StaticJSON.jtoken_to_runtime_object(loaded_token)
|
||||
else:
|
||||
_global_variables[var_val_key] = _default_global_variables[var_val_key]
|
||||
|
||||
func write_json(writer: InkSimpleJSON.Writer) -> void:
|
||||
writer.write_object_start()
|
||||
for key in _global_variables:
|
||||
var name: String = key
|
||||
var val: InkObject = _global_variables[key]
|
||||
|
||||
if self._ink_runtime.dont_save_default_values:
|
||||
if self._default_global_variables.has(name):
|
||||
if runtime_objects_equal(val, self._default_global_variables[name]):
|
||||
continue
|
||||
|
||||
writer.write_property_start(name)
|
||||
self.StaticJSON.write_runtime_object(writer, val)
|
||||
writer.write_property_end()
|
||||
writer.write_object_end()
|
||||
|
||||
func runtime_objects_equal(obj1: InkObject, obj2: InkObject) -> bool:
|
||||
if !InkUtils.are_of_same_type(obj1, obj2):
|
||||
return false
|
||||
|
||||
var bool_val: InkBoolValue = InkUtils.as_or_null(obj1, "BoolValue")
|
||||
if bool_val != null:
|
||||
return bool_val.value == InkUtils.cast(obj2, "BoolValue").value
|
||||
|
||||
var int_val: InkIntValue = InkUtils.as_or_null(obj1, "IntValue")
|
||||
if int_val != null:
|
||||
return int_val.value == InkUtils.cast(obj2, "IntValue").value
|
||||
|
||||
var float_val: InkFloatValue = InkUtils.as_or_null(obj1, "FloatValue")
|
||||
if float_val != null:
|
||||
return float_val.value == InkUtils.cast(obj2, "FloatValue").value
|
||||
|
||||
var val1: InkValue = InkUtils.as_or_null(obj1, "Value")
|
||||
var val2: InkValue = InkUtils.as_or_null(obj2, "Value")
|
||||
|
||||
if val1 != null:
|
||||
if val1.value_object is Object && val2.value_object is Object:
|
||||
return val1.value_object.equals(val2.value_object)
|
||||
else:
|
||||
return val1.value_object == val2.value_object
|
||||
|
||||
InkUtils.throw_exception(
|
||||
"FastRoughDefinitelyEquals: Unsupported runtime object type: %s" \
|
||||
% obj1.get_ink_class()
|
||||
)
|
||||
|
||||
return false
|
||||
|
||||
func get_variable_with_name(name: String, context_index = -1) -> InkObject:
|
||||
var var_value: InkObject = get_raw_variable_with_name(name, context_index)
|
||||
|
||||
var var_pointer: InkVariablePointerValue = InkUtils.as_or_null(var_value, "VariablePointerValue")
|
||||
if var_pointer:
|
||||
var_value = value_at_variable_pointer(var_pointer)
|
||||
|
||||
return var_value
|
||||
|
||||
# (String) -> { exists: bool, result: InkObject }
|
||||
func try_get_default_variable_value(name: String) -> InkTryGetResult:
|
||||
if _default_global_variables.has(name):
|
||||
return InkTryGetResult.new(true, _default_global_variables[name])
|
||||
else:
|
||||
return InkTryGetResult.new(false, null)
|
||||
|
||||
func global_variable_exists_with_name(name: String) -> bool:
|
||||
return (
|
||||
_global_variables.has(name) ||
|
||||
_default_global_variables != null && _default_global_variables.has(name)
|
||||
)
|
||||
|
||||
func get_raw_variable_with_name(name: String, context_index: int) -> InkObject:
|
||||
var var_value: InkObject = null
|
||||
|
||||
if context_index == 0 || context_index == -1:
|
||||
if self.patch != null:
|
||||
var try_result: InkTryGetResult = self.patch.try_get_global(name)
|
||||
if try_result.exists: return try_result.result
|
||||
|
||||
if _global_variables.has(name):
|
||||
return _global_variables[name]
|
||||
|
||||
if self._default_global_variables != null:
|
||||
if self._default_global_variables.has(name):
|
||||
return self._default_global_variables[name]
|
||||
|
||||
var list_item_value: InkListValue = _list_defs_origin.find_single_item_list_with_name(name)
|
||||
|
||||
if list_item_value:
|
||||
return list_item_value
|
||||
|
||||
var_value = _callstack.get_temporary_variable_with_name(name, context_index)
|
||||
|
||||
return var_value
|
||||
|
||||
# (InkVariablePointerValue) -> InkObject
|
||||
func value_at_variable_pointer(pointer: InkVariablePointerValue) -> InkObject:
|
||||
return get_variable_with_name(pointer.variable_name, pointer.context_index)
|
||||
|
||||
# (InkVariableAssignment, InkObject) -> void
|
||||
func assign(var_ass: InkVariableAssignment, value: InkObject) -> void:
|
||||
var name: String = var_ass.variable_name
|
||||
var context_index: int = -1
|
||||
|
||||
var set_global: bool = false
|
||||
if var_ass.is_new_declaration:
|
||||
set_global = var_ass.is_global
|
||||
else:
|
||||
set_global = global_variable_exists_with_name(name)
|
||||
|
||||
if var_ass.is_new_declaration:
|
||||
var var_pointer: InkVariablePointerValue = InkUtils.as_or_null(value, "VariablePointerValue")
|
||||
if var_pointer:
|
||||
var fully_resolved_variable_pointer: InkObject = resolve_variable_pointer(var_pointer)
|
||||
value = fully_resolved_variable_pointer
|
||||
else:
|
||||
var existing_pointer: InkVariablePointerValue = null # VariablePointerValue
|
||||
var first_time: bool = true
|
||||
while existing_pointer || first_time:
|
||||
first_time = false
|
||||
existing_pointer = InkUtils.as_or_null(
|
||||
get_raw_variable_with_name(name, context_index),
|
||||
"VariablePointerValue"
|
||||
)
|
||||
if existing_pointer:
|
||||
name = existing_pointer.variable_name
|
||||
context_index = existing_pointer.context_index
|
||||
set_global = (context_index == 0)
|
||||
|
||||
if set_global:
|
||||
set_global(name, value)
|
||||
else:
|
||||
_callstack.set_temporary_variable(name, value, var_ass.is_new_declaration, context_index)
|
||||
|
||||
# () -> void
|
||||
func snapshot_default_globals():
|
||||
_default_global_variables = _global_variables.duplicate()
|
||||
|
||||
# (InkObject, InkObject) -> void
|
||||
func retain_list_origins_for_assignment(old_value, new_value) -> void:
|
||||
var old_list: InkListValue = InkUtils.as_or_null(old_value, "ListValue")
|
||||
var new_list: InkListValue = InkUtils.as_or_null(new_value, "ListValue")
|
||||
|
||||
if old_list && new_list && new_list.value.size() == 0:
|
||||
new_list.value.set_initial_origin_names(old_list.value.origin_names)
|
||||
|
||||
# (String, InkObject) -> void
|
||||
func set_global(variable_name: String, value: InkObject) -> void:
|
||||
var old_value = null # InkObject
|
||||
|
||||
# Slightly different structure from upstream, since we can't use
|
||||
# try_get_global in the conditional.
|
||||
if patch != null:
|
||||
var patch_value: InkTryGetResult = patch.try_get_global(variable_name)
|
||||
if patch_value.exists:
|
||||
old_value = patch_value.result
|
||||
|
||||
if old_value == null:
|
||||
if self._global_variables.has(variable_name):
|
||||
old_value = self._global_variables[variable_name]
|
||||
|
||||
InkListValue.retain_list_origins_for_assignment(old_value, value)
|
||||
|
||||
if patch != null:
|
||||
self.patch.set_global(variable_name, value)
|
||||
else:
|
||||
self._global_variables[variable_name] = value
|
||||
|
||||
if !value.equals(old_value):
|
||||
if _batch_observing_variable_changes:
|
||||
if patch != null:
|
||||
patch.add_changed_variable(variable_name)
|
||||
elif self._changed_variables_for_batch_obs != null:
|
||||
_changed_variables_for_batch_obs.append(variable_name)
|
||||
else:
|
||||
emit_signal("variable_changed", variable_name, value)
|
||||
|
||||
# (VariablePointerValue) -> VariablePointerValue
|
||||
func resolve_variable_pointer(var_pointer: InkVariablePointerValue) -> InkVariablePointerValue:
|
||||
var context_index: int = var_pointer.context_index
|
||||
|
||||
if context_index == -1:
|
||||
context_index = get_context_index_of_variable_named(var_pointer.variable_name)
|
||||
|
||||
var value_of_variable_pointed_to = get_raw_variable_with_name(
|
||||
var_pointer.variable_name, context_index
|
||||
)
|
||||
|
||||
var double_redirection_pointer: InkVariablePointerValue = InkUtils.as_or_null(
|
||||
value_of_variable_pointed_to, "VariablePointerValue"
|
||||
)
|
||||
|
||||
if double_redirection_pointer:
|
||||
return double_redirection_pointer
|
||||
else:
|
||||
return InkVariablePointerValue.new_with_context(var_pointer.variable_name, context_index)
|
||||
|
||||
# ############################################################################ #
|
||||
|
||||
# (String) -> int
|
||||
func get_context_index_of_variable_named(var_name):
|
||||
if global_variable_exists_with_name(var_name):
|
||||
return 0
|
||||
|
||||
return _callstack.current_element_index
|
||||
|
||||
# Dictionary<String, InkObject>
|
||||
var _global_variables: Dictionary
|
||||
var _default_global_variables = null # Dictionary<String, InkObject>
|
||||
|
||||
var _callstack: InkCallStack
|
||||
var _changed_variables_for_batch_obs: InkStringSet = null
|
||||
var _list_defs_origin: InkListDefinitionsOrigin
|
||||
|
||||
# ############################################################################ #
|
||||
# GDScript extra methods
|
||||
# ############################################################################ #
|
||||
|
||||
func is_ink_class(type: String) -> bool:
|
||||
return type == "VariableState" || super.is_ink_class(type)
|
||||
|
||||
func get_ink_class() -> String:
|
||||
return "VariableState"
|
||||
|
||||
# ############################################################################ #
|
||||
# Static Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var StaticJSON: InkStaticJSON:
|
||||
get: return self._ink_runtime.json
|
||||
|
||||
var _ink_runtime:
|
||||
get: return _weak_ink_runtime.get_ref()
|
||||
var _weak_ink_runtime: WeakRef
|
||||
|
||||
func find_static_objects(ink_runtime = null):
|
||||
if ink_runtime != null:
|
||||
_weak_ink_runtime = weakref(ink_runtime)
|
||||
return
|
||||
|
||||
var runtime = Engine.get_main_loop().root.get_node("__InkRuntime")
|
||||
|
||||
InkUtils.__assert__(
|
||||
runtime != null,
|
||||
"[InkVariableStates] Could not retrieve 'InkRuntime' singleton from the scene tree."
|
||||
)
|
||||
|
||||
_weak_ink_runtime = weakref(runtime)
|
Loading…
Add table
Add a link
Reference in a new issue