From 2fa5bc78b5c4500301327bd6a334ab4fb8e04a17 Mon Sep 17 00:00:00 2001 From: yum Date: Fri, 30 Sep 2022 18:44:36 -0700 Subject: Redo FX layer Apparently the same avatar parameter can only be updated so quickly before VRChat starts dropping messages. So now we divide the board into "groups" of 8 characters. Each group can be updated relatively slowly, but all groups can be updated in parallel. Thus we can update the board group-by-group, pausing between each group. * Fix shader bugs - now there are Row05 parameters, and row00 refers to the topmost row instead of the bottom-most. * Remove outdated layer/group names files * Extend osc_ctrl.py to support encoding & sending messages * Add generate_params.py to handle creating TaSTT_params.asset * Add generate_utils.py for common code generation facilities & parameters. --- README.md | 6 - TaSTT.cs | 78 -------- TaSTT.shader | 40 ++-- TaSTT_params.asset | 31 --- cell_names.txt | 84 -------- generate_fx.py | 574 ++++++++++++++++++++++++++--------------------------- generate_params.py | 61 ++++++ generate_utils.py | 53 +++++ group_names.txt | 24 --- osc_ctrl.py | 103 ++++++++-- 10 files changed, 504 insertions(+), 550 deletions(-) delete mode 100644 TaSTT.cs delete mode 100644 TaSTT_params.asset delete mode 100644 cell_names.txt create mode 100644 generate_params.py create mode 100644 generate_utils.py delete mode 100644 group_names.txt diff --git a/README.md b/README.md index 986ca8b..4a6ce42 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,6 @@ Features: * Low-latency. * Stable. * Configurable. -* Very low parameter space usage: 25 bits at the time of writing. - * u8 TaSTT\_Letter: the letter to write at the current position - * u8 TaSTT\_Row: the row to write on. - * u8 TaSTT\_Col: the col to write on. - * bool TaSTT\_Active: whether or not to overwrite (turn this off while seeking - to a new spot). * 6x14 display grid, 80 characters per slot. * Each parameter - grid size, characters per slot, may be dialed up or down as desired. diff --git a/TaSTT.cs b/TaSTT.cs deleted file mode 100644 index d9901d6..0000000 --- a/TaSTT.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEditor; -using UnityEditor.Animations; -using UnityEngine; -using VRC.SDK3.Avatars.Components; -using VRC.SDK3.Avatars.ScriptableObjects; - -namespace TaSTT -{ - public class TaSTT : EditorWindow - { - private static TaSTT instance_; - private GameObject avatar_root_; - private AnimatorController fx_controller_; - - [MenuItem("Window/TaSTT")] - private static void ShowWindow() - { - instance_ = GetWindow(); - instance_.titleContent = new GUIContent("TaSTT"); - } - - private void Draw() - { - GUILayout.Label("TaSTT: A free VRChat STT"); - GUILayout.Label("Made with love by yum_food"); - GUILayout.Label(""); - - avatar_root_ = (GameObject)EditorGUILayout.ObjectField( - new GUIContent("Avatar Root"), avatar_root_, - typeof(GameObject), true); - fx_controller_ = (AnimatorController)EditorGUILayout.ObjectField( - new GUIContent("FX Controller"), fx_controller_, - typeof(AnimatorController), true); - - if (GUILayout.Button("Create animations!")) - { - if (avatar_root_ == null || !fx_controller_ == null) - { - // TODO(yum_food) why doesn't EditorGUILayout.HelpBox() work here? - Debug.LogError("Avatar root or FX controller are not set! Cannot create animations."); - return; - } - // TODO(yum_food) - } - if (GUILayout.Button("Create FX layer!")) - { - if (!avatar_root_ == null || !fx_controller_ == null) - { - Debug.LogError("Avatar root or FX controller are not set! Cannot create FX layer."); - return; - } - // TODO(yum_food) - } - } - - private static void CreateAnimations() - { - VRCAvatarDescriptor descriptor = avatar_root_.GetComponent(); - if (descriptor == null) - { - Debug.LogError("Failed to get avatar descriptor"); - return; - } - AnimationClip anim = new AnimationClip(); - clip.frameRate = 1f; - } - - private void OnGUI() - { - if (instance_ != null) - { - Draw(); - } - } - } -} diff --git a/TaSTT.shader b/TaSTT.shader index 8f18dae..f5ec6af 100644 --- a/TaSTT.shader +++ b/TaSTT.shader @@ -74,20 +74,20 @@ _Letter_Row04_Col11("_Letter_Row04_Col11", float) = 0 _Letter_Row04_Col12("_Letter_Row04_Col12", float) = 0 _Letter_Row04_Col13("_Letter_Row04_Col13", float) = 0 - _Letter_Row03_Col00("_Letter_Row03_Col00", float) = 0 - _Letter_Row03_Col01("_Letter_Row03_Col01", float) = 0 - _Letter_Row03_Col02("_Letter_Row03_Col02", float) = 0 - _Letter_Row03_Col03("_Letter_Row03_Col03", float) = 0 - _Letter_Row03_Col04("_Letter_Row03_Col04", float) = 0 - _Letter_Row03_Col05("_Letter_Row03_Col05", float) = 0 - _Letter_Row03_Col06("_Letter_Row03_Col06", float) = 0 - _Letter_Row03_Col07("_Letter_Row03_Col07", float) = 0 - _Letter_Row03_Col08("_Letter_Row03_Col08", float) = 0 - _Letter_Row03_Col09("_Letter_Row03_Col09", float) = 0 - _Letter_Row03_Col10("_Letter_Row03_Col10", float) = 0 - _Letter_Row03_Col11("_Letter_Row03_Col11", float) = 0 - _Letter_Row03_Col12("_Letter_Row03_Col12", float) = 0 - _Letter_Row03_Col13("_Letter_Row03_Col13", float) = 0 + _Letter_Row05_Col00("_Letter_Row05_Col00", float) = 0 + _Letter_Row05_Col01("_Letter_Row05_Col01", float) = 0 + _Letter_Row05_Col02("_Letter_Row05_Col02", float) = 0 + _Letter_Row05_Col03("_Letter_Row05_Col03", float) = 0 + _Letter_Row05_Col04("_Letter_Row05_Col04", float) = 0 + _Letter_Row05_Col05("_Letter_Row05_Col05", float) = 0 + _Letter_Row05_Col06("_Letter_Row05_Col06", float) = 0 + _Letter_Row05_Col07("_Letter_Row05_Col07", float) = 0 + _Letter_Row05_Col08("_Letter_Row05_Col08", float) = 0 + _Letter_Row05_Col09("_Letter_Row05_Col09", float) = 0 + _Letter_Row05_Col10("_Letter_Row05_Col10", float) = 0 + _Letter_Row05_Col11("_Letter_Row05_Col11", float) = 0 + _Letter_Row05_Col12("_Letter_Row05_Col12", float) = 0 + _Letter_Row05_Col13("_Letter_Row05_Col13", float) = 0 } SubShader { @@ -268,7 +268,7 @@ float CHAR_ROW = floor(i.uv.y * CHAR_ROWS); // ok now this is epic - if (CHAR_ROW == 0) { + if (CHAR_ROW == 5) { if (CHAR_COL == 0) { return _Letter_Row00_Col00; } else if (CHAR_COL == 1) { @@ -298,7 +298,7 @@ } else if (CHAR_COL == 13) { return _Letter_Row00_Col13; } - } else if (CHAR_ROW == 1) { + } else if (CHAR_ROW == 4) { if (CHAR_COL == 0) { return _Letter_Row01_Col00; } else if (CHAR_COL == 1) { @@ -328,7 +328,7 @@ } else if (CHAR_COL == 13) { return _Letter_Row01_Col13; } - } else if (CHAR_ROW == 2) { + } else if (CHAR_ROW == 3) { if (CHAR_COL == 0) { return _Letter_Row02_Col00; } else if (CHAR_COL == 1) { @@ -358,7 +358,7 @@ } else if (CHAR_COL == 13) { return _Letter_Row02_Col13; } - } else if (CHAR_ROW == 3) { + } else if (CHAR_ROW == 2) { if (CHAR_COL == 0) { return _Letter_Row03_Col00; } else if (CHAR_COL == 1) { @@ -388,7 +388,7 @@ } else if (CHAR_COL == 13) { return _Letter_Row03_Col13; } - } else if (CHAR_ROW == 4) { + } else if (CHAR_ROW == 1) { if (CHAR_COL == 0) { return _Letter_Row04_Col00; } else if (CHAR_COL == 1) { @@ -418,7 +418,7 @@ } else if (CHAR_COL == 13) { return _Letter_Row04_Col13; } - } else if (CHAR_ROW == 5) { + } else if (CHAR_ROW == 0) { if (CHAR_COL == 0) { return _Letter_Row05_Col00; } else if (CHAR_COL == 1) { diff --git a/TaSTT_params.asset b/TaSTT_params.asset deleted file mode 100644 index 4c79902..0000000 --- a/TaSTT_params.asset +++ /dev/null @@ -1,31 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: -1506855854, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} - m_Name: TaSTT_params - m_EditorClassIdentifier: - parameters: - - name: TaSTT_Letter - valueType: 0 - saved: 0 - defaultValue: 0 - - name: TaSTT_Row - valueType: 0 - saved: 0 - defaultValue: 0 - - name: TaSTT_Col - valueType: 0 - saved: 0 - defaultValue: 0 - - name: TaSTT_Active - valueType: 2 - saved: 0 - defaultValue: 0 diff --git a/cell_names.txt b/cell_names.txt deleted file mode 100644 index 1000cd1..0000000 --- a/cell_names.txt +++ /dev/null @@ -1,84 +0,0 @@ -_Letter_Row00_Col00 -_Letter_Row00_Col01 -_Letter_Row00_Col02 -_Letter_Row00_Col03 -_Letter_Row00_Col04 -_Letter_Row00_Col05 -_Letter_Row00_Col06 -_Letter_Row00_Col07 -_Letter_Row00_Col08 -_Letter_Row00_Col09 -_Letter_Row00_Col10 -_Letter_Row00_Col11 -_Letter_Row00_Col12 -_Letter_Row00_Col13 -_Letter_Row01_Col00 -_Letter_Row01_Col01 -_Letter_Row01_Col02 -_Letter_Row01_Col03 -_Letter_Row01_Col04 -_Letter_Row01_Col05 -_Letter_Row01_Col06 -_Letter_Row01_Col07 -_Letter_Row01_Col08 -_Letter_Row01_Col09 -_Letter_Row01_Col10 -_Letter_Row01_Col11 -_Letter_Row01_Col12 -_Letter_Row01_Col13 -_Letter_Row02_Col00 -_Letter_Row02_Col01 -_Letter_Row02_Col02 -_Letter_Row02_Col03 -_Letter_Row02_Col04 -_Letter_Row02_Col05 -_Letter_Row02_Col06 -_Letter_Row02_Col07 -_Letter_Row02_Col08 -_Letter_Row02_Col09 -_Letter_Row02_Col10 -_Letter_Row02_Col11 -_Letter_Row02_Col12 -_Letter_Row02_Col13 -_Letter_Row03_Col00 -_Letter_Row03_Col01 -_Letter_Row03_Col02 -_Letter_Row03_Col03 -_Letter_Row03_Col04 -_Letter_Row03_Col05 -_Letter_Row03_Col06 -_Letter_Row03_Col07 -_Letter_Row03_Col08 -_Letter_Row03_Col09 -_Letter_Row03_Col10 -_Letter_Row03_Col11 -_Letter_Row03_Col12 -_Letter_Row03_Col13 -_Letter_Row04_Col00 -_Letter_Row04_Col01 -_Letter_Row04_Col02 -_Letter_Row04_Col03 -_Letter_Row04_Col04 -_Letter_Row04_Col05 -_Letter_Row04_Col06 -_Letter_Row04_Col07 -_Letter_Row04_Col08 -_Letter_Row04_Col09 -_Letter_Row04_Col10 -_Letter_Row04_Col11 -_Letter_Row04_Col12 -_Letter_Row04_Col13 -_Letter_Row05_Col00 -_Letter_Row05_Col01 -_Letter_Row05_Col02 -_Letter_Row05_Col03 -_Letter_Row05_Col04 -_Letter_Row05_Col05 -_Letter_Row05_Col06 -_Letter_Row05_Col07 -_Letter_Row05_Col08 -_Letter_Row05_Col09 -_Letter_Row05_Col10 -_Letter_Row05_Col11 -_Letter_Row05_Col12 -_Letter_Row05_Col13 diff --git a/generate_fx.py b/generate_fx.py index ba1d590..28d6550 100644 --- a/generate_fx.py +++ b/generate_fx.py @@ -15,10 +15,18 @@ # where we're transitioning to. # 12. %TRANSITION_THRESHOLD% - the threshold to use when transitioning. +from generate_utils import replaceMacros +from generate_utils import getDummyParam +from generate_utils import getLayerParam +from generate_utils import getSelectParam +from generate_utils import getEnableParam +from generate_utils import getShaderParam +from generate_utils import getAnimationPath +from generate_utils import NUM_LAYERS +from generate_utils import CHARS_PER_CELL + # To debug, I recommend setting these values low and manually moving things # around in the animator. Then run using Lyuma's avatar 3.0 emulator. -NUM_ROWS=6 -NUM_COLS=14 NUM_LETTERS=80 params = {} @@ -34,33 +42,20 @@ def get_u2(class_id, state): # These !u! and & numbers are, respectively, a class ID and an instance ID. # The instance ID begins with the class ID then has a 5-digit suffix. params["ANIMATOR_CONTROLLER_U"] = "91" -params["ANIMATOR_HEADER_U2"] = "9100000" # this is a special value +params["ANIMATOR_HEADER_U2"] = "9100000" params["ANIMATOR_STATE_MACHINE_U"] = "1107" -params["TASTT_LAYER_U2"] = get_u2("1107", state) params["MONO_BEHAVIOUR_U"] = "114" -params["SET_LETTERS_SCRIPT_U2"] = get_u2("114", state) params["ANIMATOR_STATE_U"] = "1102" -params["TASTT_DEFAULT_STATE_U2"] = get_u2("1102", state) -params["TASTT_ACTIVE_STATE_U2"] = get_u2("1102", state) params["ANIMATOR_STATE_TRANSITION_U"] = "1101" -params["TASTT_ACTIVE_STATE_TRANSITION_U2"] = get_u2("1101", state) -params["TASTT_RESTART_TRANSITION_U2"] = get_u2("1101", state) HEADER=""" %YAML 1.1 %TAG !u! tag:unity3d.com,2011: -"""[1:] - -# Generates the sed cmd args required to replace all parameters defined in -# $1, which is an associative array like `params`. -def replaceMacros(lines, macro_defs): - for k,v in macro_defs.items(): - lines = lines.replace("%" + k + "%", v) - return lines +"""[1:][:-1] def genHeader(): return replaceMacros(HEADER, params) @@ -75,11 +70,11 @@ AnimatorController: m_PrefabAsset: {fileID: 0} m_Name: TaSTT_fx serializedVersion: 5 -"""[1:] +"""[1:][:-1] ANIMATOR_PARAMETER_HEADER = """ m_AnimatorParameters: -"""[1:] +"""[1:][:-1] ANIMATOR_PARAMETER_INT = """ - m_Name: %ANIMATOR_PARAMETER_NAME% @@ -88,7 +83,7 @@ ANIMATOR_PARAMETER_INT = """ m_DefaultInt: 0 m_DefaultBool: 0 m_Controller: {fileID: 0} -"""[1:] +"""[1:][:-1] ANIMATOR_PARAMETER_BOOL = """ - m_Name: %ANIMATOR_PARAMETER_NAME% @@ -97,42 +92,26 @@ ANIMATOR_PARAMETER_BOOL = """ m_DefaultInt: 0 m_DefaultBool: 0 m_Controller: {fileID: 0} -"""[1:] +"""[1:][:-1] ANIMATOR_LAYER_HEADER = """ m_AnimatorLayers: -"""[1:] +"""[1:][:-1] -# We have a single animator layer which does everything. ANIMATOR_LAYER_TASTT = """ - serializedVersion: 5 - m_Name: TaSTT + m_Name: %TASTT_LAYER_NAME% m_StateMachine: {fileID: %TASTT_LAYER_U2%} m_Mask: {fileID: 0} m_Motions: [] m_Behaviours: [] m_BlendingMode: 0 m_SyncedLayerIndex: -1 - m_DefaultWeight: 0 - m_IKPass: 0 - m_SyncedLayerAffectsTiming: 0 - m_Controller: {fileID: %ANIMATOR_HEADER_U2%} -"""[1:] - -ANIMATOR_LAYER_CELL_ANIM = """ - - serializedVersion: 5 - m_Name: %LAYER_NAME% - m_StateMachine: {fileID: %LAYER_STATE_MACHINE_U2%} - m_Mask: {fileID: 0} - m_Motions: [] - m_Behaviours: [] - m_BlendingMode: 0 - m_SyncedLayerIndex: -1 m_DefaultWeight: 1 m_IKPass: 0 m_SyncedLayerAffectsTiming: 0 m_Controller: {fileID: %ANIMATOR_HEADER_U2%} -"""[1:] +"""[1:][:-1] GROUP_NAMES = [ "_Letter_Row00_Col00_03", @@ -252,19 +231,33 @@ def genAnimator(state): print(replaceMacros(ANIMATOR_HEADER, params)) print(ANIMATOR_PARAMETER_HEADER) - params["ANIMATOR_PARAMETER_NAME"] = "TaSTT_Letter" - print(replaceMacros(ANIMATOR_PARAMETER_INT, params)) - params["ANIMATOR_PARAMETER_NAME"] = "TaSTT_Row" - print(replaceMacros(ANIMATOR_PARAMETER_INT, params)) - params["ANIMATOR_PARAMETER_NAME"] = "TaSTT_Col" - print(replaceMacros(ANIMATOR_PARAMETER_INT, params)) - params["ANIMATOR_PARAMETER_NAME"] = "TaSTT_Active" - print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) - params["ANIMATOR_PARAMETER_NAME"] = "TaSTT_Dummy" + params["ANIMATOR_PARAMETER_NAME"] = getDummyParam() print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) + for i in range(0, NUM_LAYERS): + params["ANIMATOR_PARAMETER_NAME"] = getLayerParam(i) + print(replaceMacros(ANIMATOR_PARAMETER_INT, params)) + + params["ANIMATOR_PARAMETER_NAME"] = getSelectParam(i, 0) + print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) + + params["ANIMATOR_PARAMETER_NAME"] = getSelectParam(i, 1) + print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) + + params["ANIMATOR_PARAMETER_NAME"] = getSelectParam(i, 2) + print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) + + params["ANIMATOR_PARAMETER_NAME"] = getEnableParam(i) + print(replaceMacros(ANIMATOR_PARAMETER_BOOL, params)) + + print(replaceMacros(ANIMATOR_LAYER_HEADER, params)) - print(replaceMacros(ANIMATOR_LAYER_TASTT, params)) + + for i in range(0, NUM_LAYERS): + params[getLayerParam(i) + "_LAYER_U2"] = get_u2("1107", state) + params["TASTT_LAYER_U2"] = params[getLayerParam(i) + "_LAYER_U2"] + params["TASTT_LAYER_NAME"] = getLayerParam(i) + print(replaceMacros(ANIMATOR_LAYER_TASTT, params)) genAnimator(state) TASTT_LAYER_HEADER = """ @@ -275,15 +268,15 @@ AnimatorStateMachine: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: TaSTT + m_Name: %TASTT_LAYER_NAME% m_ChildStates: -"""[1:] +"""[1:][:-1] TASTT_LAYER_HEADER_CHILD_STATE = """ - serializedVersion: 1 m_State: {fileID: %TASTT_STATE_U2%} m_Position: {x: 330, y: -60, z: 0} -"""[1:] +"""[1:][:-1] TASTT_LAYER_FOOTER = """ m_ChildStateMachines: [] @@ -296,23 +289,26 @@ TASTT_LAYER_FOOTER = """ m_ExitPosition: {x: 800, y: 120, z: 0} m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} m_DefaultState: {fileID: %TASTT_DEFAULT_STATE_U2%} -"""[1:] +"""[1:][:-1] -# Default state. -# One transition to TaSTT_Active. -TASTT_DEFAULT_STATE = """ ---- !u!%ANIMATOR_STATE_U% &%TASTT_DEFAULT_STATE_U2% +# State with one transition. +# Params: +# %TASTT_STATE_NAME%: the name of this state +# %TASTT_STATE_TRANSITION_U2%: the U2 of the transition to the next state +# %TASTT_STATE_TRANSITION_U2% +TASTT_UNARY_STATE = """ +--- !u!%ANIMATOR_STATE_U% &%TASTT_STATE_U2% AnimatorState: serializedVersion: 6 m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: TaSTT_Do_Nothing + m_Name: %TASTT_STATE_NAME% m_Speed: 1 m_CycleOffset: 0 m_Transitions: - - {fileID: %TASTT_ACTIVE_STATE_TRANSITION_U2%} + - {fileID: %TASTT_STATE_TRANSITION_U2%} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -328,61 +324,28 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: -"""[1:] +"""[1:][:-1] -# Transition from TaSTT_Do_nothing. to TaSTT_Active. +# State with two transitions. # Params: -# %TASTT_ACTIVE_STATE_TRANSITION_U2% -# %TASTT_ROW_STATE_U2% - address of row state we're transitioning to -TASTT_ACTIVE_STATE_TRANSITION = """ ---- !u!1101 &%TASTT_ACTIVE_STATE_TRANSITION_U2% -AnimatorStateTransition: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: - m_Conditions: - - m_ConditionMode: 1 - m_ConditionEvent: TaSTT_Active - m_EventTreshold: 1 - m_DstStateMachine: {fileID: 0} - m_DstState: {fileID: %TASTT_ACTIVE_STATE_U2%} - m_Solo: 0 - m_Mute: 0 - m_IsExit: 0 - serializedVersion: 3 - m_TransitionDuration: 0 - m_TransitionOffset: 0 - m_ExitTime: 0.75 - m_HasExitTime: 0 - m_HasFixedDuration: 1 - m_InterruptionSource: 0 - m_OrderedInterruption: 1 - m_CanTransitionToSelf: 1 -"""[1:] - -# State reached when TaSTT_Active = True. -# One transition per row. -TASTT_ACTIVE_STATE_HEADER = """ ---- !u!1102 &%TASTT_ACTIVE_STATE_U2% +# %TASTT_STATE_NAME%: the name of this state +# %TASTT_STATE_TRANSITION_0_U2% +# %TASTT_STATE_TRANSITION_1_U2% +# %TASTT_STATE_TRANSITION_U2% +TASTT_BINARY_STATE = """ +--- !u!%ANIMATOR_STATE_U% &%TASTT_STATE_U2% AnimatorState: serializedVersion: 6 m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: TaSTT_Active + m_Name: %TASTT_STATE_NAME% m_Speed: 1 m_CycleOffset: 0 m_Transitions: -"""[1:] - -TASTT_ACTIVE_STATE_HEADER_TRANSITION = """ - - {fileID: %TASTT_TRANSITION_U2%} -"""[1:] - -TASTT_ACTIVE_STATE_FOOTER = """ + - {fileID: %TASTT_STATE_TRANSITION_0_U2%} + - {fileID: %TASTT_STATE_TRANSITION_1_U2%} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -398,47 +361,40 @@ TASTT_ACTIVE_STATE_FOOTER = """ m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: -"""[1:] +"""[1:][:-1] -# Transition from TaSTT_Active to TaSTT_Row*. -# Params: -# TRANSITION_THRESHOLD: The row to transition to (int). -# DST_STATE_U2 -TASTT_ROW_STATE_TRANSITION = """ ---- !u!1101 &%TRANSITION_U2% -AnimatorStateTransition: +TASTT_UNARY_STATE = """ +--- !u!%ANIMATOR_STATE_U% &%TASTT_STATE_U2% +AnimatorState: + serializedVersion: 6 m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: - m_Conditions: - - m_ConditionMode: 6 - m_ConditionEvent: TaSTT_Row - m_EventTreshold: %TRANSITION_THRESHOLD% - m_DstStateMachine: {fileID: 0} - m_DstState: {fileID: %DST_STATE_U2%} - m_Solo: 0 - m_Mute: 0 - m_IsExit: 0 - serializedVersion: 3 - m_TransitionDuration: 0 - m_TransitionOffset: 0 - m_ExitTime: 0.75 - m_HasExitTime: 0 - m_HasFixedDuration: 1 - m_InterruptionSource: 0 - m_OrderedInterruption: 1 - m_CanTransitionToSelf: 1 -"""[1:] + m_Name: %TASTT_STATE_NAME% + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: %TASTT_STATE_TRANSITION_U2%} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 0 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +"""[1:][:-1] -# State reached after TaSTT_Active. -# One transition per column. -# Params: -# %TASTT_STATE_NAME%: TaSTT_Row[0-9][0-9]. -# %TASTT_TRANSITION_U2% -TASTT_ROW_STATE_HEADER = """ ---- !u!1102 &%TASTT_STATE_U2% +TASTT_NARY_STATE_HEADER = """ +--- !u!%ANIMATOR_STATE_U% &%TASTT_STATE_U2% AnimatorState: serializedVersion: 6 m_ObjectHideFlags: 1 @@ -449,13 +405,13 @@ AnimatorState: m_Speed: 1 m_CycleOffset: 0 m_Transitions: -"""[1:] +"""[1:][:-1] -TASTT_ROW_STATE_HEADER_TRANSITION = """ - - {fileID: %TASTT_TRANSITION_U2%} -"""[1:] +TASTT_NARY_STATE_HEADER_TRANSITION = """ + - {fileID: %TASTT_STATE_TRANSITION_U2%} +"""[1:][:-1] -TASTT_ROW_STATE_FOOTER = """ +TASTT_NARY_STATE_FOOTER = """ m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -471,14 +427,18 @@ TASTT_ROW_STATE_FOOTER = """ m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: -"""[1:] +"""[1:][:-1] -# Transition from TaSTT_Row* to TaSTT_Row*_Col*. +# Transition from TaSTT_Do_nothing. to TaSTT_Active. # Params: -# TRANSITION_THRESHOLD: The col to transition to (int). -# DST_STATE_U2 -TASTT_COL_STATE_TRANSITION = """ ---- !u!1101 &%TASTT_TRANSITION_U2% +# %BOOL_PARAM% - the name of the parameter to branch on +# %THRESHOLD% - the condition to branch on (1 == true) +# %TASTT_ACTIVE_STATE_TRANSITION_U2% +# %TASTT_ROW_STATE_U2% - address of row state we're transitioning to +# A bizarre quirk: when branching false, m_ConditionMode = 2; else +# m_ConditionMode = 1. +TASTT_BOOL_STATE_TRANSITION = """ +--- !u!1101 &%TASTT_STATE_TRANSITION_U2% AnimatorStateTransition: m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} @@ -486,9 +446,9 @@ AnimatorStateTransition: m_PrefabAsset: {fileID: 0} m_Name: m_Conditions: - - m_ConditionMode: 6 - m_ConditionEvent: TaSTT_Col - m_EventTreshold: %TRANSITION_THRESHOLD% + - m_ConditionMode: %MODE% + m_ConditionEvent: %BOOL_PARAM% + m_EventTreshold: %THRESHOLD% m_DstStateMachine: {fileID: 0} m_DstState: {fileID: %DST_STATE_U2%} m_Solo: 0 @@ -503,55 +463,10 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 -"""[1:] +"""[1:][:-1] -# State reached after TaSTT_Row*. -# One transition per letter. -# Params: -# %TASTT_STATE_NAME%: TaSTT_Row[0-9][0-9]_Col[0-9][0-9] -# %TASTT_TRANSITION_U2% -TASTT_COL_STATE_HEADER = """ ---- !u!1102 &%TASTT_STATE_U2% -AnimatorState: - serializedVersion: 6 - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: %TASTT_STATE_NAME% - m_Speed: 1 - m_CycleOffset: 0 - m_Transitions: -"""[1:] - -TASTT_COL_STATE_HEADER_TRANSITION = """ - - {fileID: %TASTT_TRANSITION_U2%} -"""[1:] - -TASTT_COL_STATE_FOOTER = """ - m_StateMachineBehaviours: [] - m_Position: {x: 50, y: 50, z: 0} - m_IKOnFeet: 0 - m_WriteDefaultValues: 0 - m_Mirror: 0 - m_SpeedParameterActive: 0 - m_MirrorParameterActive: 0 - m_CycleOffsetParameterActive: 0 - m_TimeParameterActive: 0 - m_Motion: {fileID: 0} - m_Tag: - m_SpeedParameter: - m_MirrorParameter: - m_CycleOffsetParameter: - m_TimeParameter: -""" - -# Transition from TaSTT_Row*_Col* to TaSTT_Row*_Col*_Letter*. -# Params: -# TRANSITION_THRESHOLD: The row to transition to (int). -# DST_STATE_U2 -TASTT_LETTER_STATE_TRANSITION = """ ---- !u!1101 &%TASTT_TRANSITION_U2% +TASTT_INT_STATE_TRANSITION = """ +--- !u!1101 &%TASTT_STATE_TRANSITION_U2% AnimatorStateTransition: m_ObjectHideFlags: 1 m_CorrespondingSourceObject: {fileID: 0} @@ -560,7 +475,7 @@ AnimatorStateTransition: m_Name: m_Conditions: - m_ConditionMode: 6 - m_ConditionEvent: TaSTT_Letter + m_ConditionEvent: %INT_PARAM% m_EventTreshold: %TRANSITION_THRESHOLD% m_DstStateMachine: {fileID: 0} m_DstState: {fileID: %DST_STATE_U2%} @@ -568,7 +483,7 @@ AnimatorStateTransition: m_Mute: 0 m_IsExit: 0 serializedVersion: 3 - m_TransitionDuration: 0 + m_TransitionDuration: 0.02 m_TransitionOffset: 0 m_ExitTime: 0.75 m_HasExitTime: 0 @@ -576,7 +491,7 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 -"""[1:] +"""[1:][:-1] # State reached after TaSTT_Row*_Col*. # One transition back up to TaSTT_Do_Nothing. @@ -597,7 +512,7 @@ AnimatorState: m_Speed: 1 m_CycleOffset: 0 m_Transitions: - - {fileID: %TASTT_RESTART_TRANSITION_U2%} + - {fileID: %TASTT_STATE_TRANSITION_U2%} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -613,7 +528,7 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: -"""[1:] +"""[1:][:-1] TASTT_RESTART_TRANSITION = """ --- !u!1101 &%TASTT_RESTART_TRANSITION_U2% @@ -641,7 +556,7 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 -""" +"""[1:][:-1] def getAnimationGuid(anim_meta_filename): with open(anim_meta_filename, 'r') as f: @@ -649,108 +564,185 @@ def getAnimationGuid(anim_meta_filename): if "guid" in line: return line.split()[1] -def genTasttLayer(state): +def getDefaultStateName(which_layer): + return "TaSTT_Do_Nothing" + +def getActiveStateName(which_layer): + return "TaSTT_Active" + +def getS0StateName(which_layer, s0): + return "TaSTT_S%02d" % (s0) + +def getS1StateName(which_layer, s0, s1): + return "TaSTT_S%02d_S%02d" % (s0, s1) + +def getS2StateName(which_layer, s0, s1, s2): + return "TaSTT_S%02d_S%02d_S%02d" % (s0, s1, s2) + +def getLetterStateName(which_layer, s0, s1, s2, letter): + return "TaSTT_S%02d_S%02d_S%02d_L%03d" % (s0, s1, s2, letter) + +def genTasttLayer(state, which_layer): # Generate return-home transition - print(replaceMacros(TASTT_RESTART_TRANSITION, params)) + params["TASTT_RETURN_HOME_TRANSITION_%02d_U2" % which_layer] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_U2"] = params["TASTT_RETURN_HOME_TRANSITION_%02d_U2" % which_layer] + params["BOOL_PARAM"] = getDummyParam() + params["THRESHOLD"] = str(0) + params["MODE"] = str(2) # See comment above TASTT_BOOL_STATE_TRANSITION. + params["DEFAULT_STATE_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params["DEFAULT_STATE_U2"] + print(replaceMacros(TASTT_BOOL_STATE_TRANSITION, params)) # Default state. - print(replaceMacros(TASTT_DEFAULT_STATE, params)) + params["TASTT_STATE_U2"] = params["DEFAULT_STATE_U2"] + params["TASTT_STATE_NAME"] = getDefaultStateName(which_layer) + params["TASTT_STATE_TRANSITION_U2"] = get_u2("1101", state) + print(replaceMacros(TASTT_UNARY_STATE, params)) # Active state transition. - print(replaceMacros(TASTT_ACTIVE_STATE_TRANSITION, params)) + params["BOOL_PARAM"] = getEnableParam(which_layer) + params["THRESHOLD"] = str(1) + params["MODE"] = str(1) # See comment above TASTT_BOOL_STATE_TRANSITION. + params["ACTIVE_STATE_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params["ACTIVE_STATE_U2"] + print(replaceMacros(TASTT_BOOL_STATE_TRANSITION, params)) # Active state. - print(replaceMacros(TASTT_ACTIVE_STATE_HEADER, params)) - for row in range(0, NUM_ROWS): - params["TASTT_TRANSITION_ROW%02d_U2" % row] = get_u2("1101", state) - params["TASTT_TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_U2" % row] - print(replaceMacros(TASTT_ACTIVE_STATE_HEADER_TRANSITION, params)) - print(replaceMacros(TASTT_ACTIVE_STATE_FOOTER, params)) - - # Row state transitions (one per row). - for row in range(0, NUM_ROWS): - params["TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_U2" % row] - params["TRANSITION_THRESHOLD"] = str(row) - params["TASTT_ROW%02d_STATE_U2" % row] = get_u2("1102", state) - params["DST_STATE_U2"] = params["TASTT_ROW%02d_STATE_U2" % row] - print(replaceMacros(TASTT_ROW_STATE_TRANSITION, params)) - - # Row states (one per row).. - for row in range(0, NUM_ROWS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_STATE_U2" % row] - params["TASTT_STATE_NAME"] = "TaSTT_Row%02d" % row - print(replaceMacros(TASTT_ROW_STATE_HEADER, params)) - for col in range(0, NUM_COLS): - params["TASTT_TRANSITION_ROW%02d_COL%02d_U2" % (row, col)] = get_u2("1101", state) - params["TASTT_TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_COL%02d_U2" % (row, col)] - print(replaceMacros(TASTT_ROW_STATE_HEADER_TRANSITION, params)) - print(replaceMacros(TASTT_ROW_STATE_FOOTER, params)) - - # Column state transitions (one per row * column). - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - params["TASTT_TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_COL%02d_U2" % (row, col)] - params["TRANSITION_THRESHOLD"] = str(col) - params["TASTT_ROW%02d_COL%02d_STATE_U2" % (row, col)] = get_u2("1102", state) - params["DST_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_STATE_U2" % (row, col)] - print(replaceMacros(TASTT_COL_STATE_TRANSITION, params)) - - # Column states (one per row * column). - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_STATE_U2" % (row, col)] - params["TASTT_STATE_NAME"] = "TaSTT_Row%02d_Col%02d" % (row, - col) - print(replaceMacros(TASTT_COL_STATE_HEADER, params)) - for letter in range(0, NUM_LETTERS): - params["TASTT_TRANSITION_ROW%02d_COL%02d_LETTER%02d_U2" % (row, col, letter)] = get_u2("1101", state) - params["TASTT_TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_COL%02d_LETTER%02d_U2" % (row, col, letter)] - print(replaceMacros(TASTT_COL_STATE_HEADER_TRANSITION, params)) - print(replaceMacros(TASTT_COL_STATE_FOOTER, params)) - - # Letter state transitions (one per row * column * letter). - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - for letter in range(0, NUM_LETTERS): - params["TASTT_TRANSITION_U2"] = params["TASTT_TRANSITION_ROW%02d_COL%02d_LETTER%02d_U2" % (row, col, letter)] - params["TRANSITION_THRESHOLD"] = str(letter) - params["TASTT_ROW%02d_COL%02d_LETTER%02d_STATE_U2" % (row, col, letter)] = get_u2("1102", state) - params["DST_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_LETTER%02d_STATE_U2" % (row, col, letter)] - print(replaceMacros(TASTT_LETTER_STATE_TRANSITION, params)) - - # Letter states (one per row * column * letter). - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - for letter in range(0, NUM_LETTERS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_LETTER%02d_STATE_U2" % (row, col, letter)] - params["TASTT_STATE_NAME"] = "TaSTT_Row%02d_Col%02d_Letter%02d" % (row, col, letter) - # Get the GUID of the animation we will play here. - anim_meta_filename = "generated/animations/_Letter_Row%02d_Col%02d_Letter%02d.anim.meta" % (row, col, letter) - params["TASTT_ANIM_GUID"] = getAnimationGuid(anim_meta_filename) - print(replaceMacros(TASTT_LETTER_STATE, params)) + params["TASTT_STATE_U2"] = params["ACTIVE_STATE_U2"] + params["TASTT_STATE_NAME"] = getActiveStateName(which_layer) + params[getS0StateName(which_layer, 0) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_0_U2"] = params[getS0StateName(which_layer, 0) + "_TRANSITION_U2"] + params[getS0StateName(which_layer, 1) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_1_U2"] = params[getS0StateName(which_layer, 1) + "_TRANSITION_U2"] + print(replaceMacros(TASTT_BINARY_STATE, params)) + + # S0 state transition. + for s0 in range(0,2): + params["TASTT_STATE_TRANSITION_U2"] = params[getS0StateName(which_layer, s0) + "_TRANSITION_U2"] + params["BOOL_PARAM"] = getSelectParam(which_layer, 0) + params["THRESHOLD"] = str(s0) + params["MODE"] = str(2 - s0) # See comment above TASTT_BOOL_STATE_TRANSITION. + params[getS0StateName(which_layer, s0) + "_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params[getS0StateName(which_layer, s0) + "_U2"] + print(replaceMacros(TASTT_BOOL_STATE_TRANSITION, params)) + + # S0 state. + for s0 in range(0,2): + params["TASTT_STATE_U2"] = params[getS0StateName(which_layer, s0) + "_U2"] + params["TASTT_STATE_NAME"] = getS0StateName(which_layer, s0) + params[getS1StateName(which_layer, s0, 0) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_0_U2"] = params[getS1StateName(which_layer, s0, 0) + "_TRANSITION_U2"] + params[getS1StateName(which_layer, s0, 1) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_1_U2"] = params[getS1StateName(which_layer, s0, 1) + "_TRANSITION_U2"] + print(replaceMacros(TASTT_BINARY_STATE, params)) + + # S1 state transition. + for s0 in range(0,2): + for s1 in range(0,2): + params["TASTT_STATE_TRANSITION_U2"] = params[getS1StateName(which_layer, s0, s1) + "_TRANSITION_U2"] + params["BOOL_PARAM"] = getSelectParam(which_layer, 1) + params["THRESHOLD"] = str(s1) + params["MODE"] = str(2 - s1) # See comment above TASTT_BOOL_STATE_TRANSITION. + params[getS1StateName(which_layer, s0, s1) + "_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params[getS1StateName(which_layer, s0, s1) + "_U2"] + print(replaceMacros(TASTT_BOOL_STATE_TRANSITION, params)) + + # S1 state. + for s0 in range(0,2): + for s1 in range(0,2): + params["TASTT_STATE_U2"] = params[getS1StateName(which_layer, s0, s1) + "_U2"] + params["TASTT_STATE_NAME"] = getS1StateName(which_layer, s0, s1) + params[getS2StateName(which_layer, s0, s1, 0) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_0_U2"] = params[getS2StateName(which_layer, s0, s1, 0) + "_TRANSITION_U2"] + params[getS2StateName(which_layer, s0, s1, 1) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_1_U2"] = params[getS2StateName(which_layer, s0, s1, 1) + "_TRANSITION_U2"] + print(replaceMacros(TASTT_BINARY_STATE, params)) + + # S2 state transition. + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + params["TASTT_STATE_TRANSITION_U2"] = params[getS2StateName(which_layer, s0, s1, s2) + "_TRANSITION_U2"] + params["BOOL_PARAM"] = getSelectParam(which_layer, 2) + params["THRESHOLD"] = str(s2) + params["MODE"] = str(2 - s2) # See comment above TASTT_BOOL_STATE_TRANSITION. + params[getS2StateName(which_layer, s0, s1, s2) + "_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params[getS2StateName(which_layer, s0, s1, s2) + "_U2"] + print(replaceMacros(TASTT_BOOL_STATE_TRANSITION, params)) + + # S2 state. + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + params["TASTT_STATE_U2"] = params[getS2StateName(which_layer, s0, s1, s2) + "_U2"] + params["TASTT_STATE_NAME"] = getS2StateName(which_layer, s0, s1, s2) + print(replaceMacros(TASTT_NARY_STATE_HEADER, params)) + for letter in range(0, CHARS_PER_CELL): + params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_TRANSITION_U2"] = get_u2("1101", state) + params["TASTT_STATE_TRANSITION_U2"] = params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_TRANSITION_U2"] + print(replaceMacros(TASTT_NARY_STATE_HEADER_TRANSITION, params)) + print(replaceMacros(TASTT_NARY_STATE_FOOTER, params)) + + # Letter state transition. + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + for letter in range(0, CHARS_PER_CELL): + params["TASTT_STATE_TRANSITION_U2"] = params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_TRANSITION_U2"] + params["INT_PARAM"] = getLayerParam(which_layer) + params["TRANSITION_THRESHOLD"] = str(letter) + params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_U2"] = get_u2("1102", state) + params["DST_STATE_U2"] = params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_U2"] + print(replaceMacros(TASTT_INT_STATE_TRANSITION, params)) + + # Letter state. + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + for letter in range(0, CHARS_PER_CELL): + params["TASTT_STATE_U2"] = params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_U2"] + params["TASTT_STATE_NAME"] = getLetterStateName(which_layer, s0, s1, s2, letter) + params["TASTT_STATE_TRANSITION_U2"] = params["TASTT_RETURN_HOME_TRANSITION_%02d_U2" % which_layer] + anim_meta_filename = getAnimationPath(getShaderParam(which_layer, s0, s1, s2), letter) + ".meta" + params["TASTT_ANIM_GUID"] = getAnimationGuid(anim_meta_filename) + print(replaceMacros(TASTT_LETTER_STATE, params)) # TaSTT layer. + params["TASTT_LAYER_U2"] = params[getLayerParam(which_layer) + "_LAYER_U2"] + + params["TASTT_LAYER_NAME"] = getLayerParam(which_layer) print(replaceMacros(TASTT_LAYER_HEADER, params)) - params["TASTT_STATE_U2"] = params["TASTT_DEFAULT_STATE_U2"] + params["TASTT_STATE_U2"] = params["DEFAULT_STATE_U2"] print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) - params["TASTT_STATE_U2"] = params["TASTT_ACTIVE_STATE_U2"] + params["TASTT_STATE_U2"] = params["ACTIVE_STATE_U2"] print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) - for row in range(0, NUM_ROWS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_STATE_U2" % row] + for s0 in range(0,2): + params["TASTT_STATE_U2"] = params[getS0StateName(which_layer, s0) + "_U2"] print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_STATE_U2" % (row, col)] + for s0 in range(0,2): + for s1 in range(0,2): + params["TASTT_STATE_U2"] = params[getS1StateName(which_layer, s0, s1) + "_U2"] print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) - for row in range(0, NUM_ROWS): - for col in range(0, NUM_COLS): - for letter in range(0, NUM_LETTERS): - params["TASTT_STATE_U2"] = params["TASTT_ROW%02d_COL%02d_LETTER%02d_STATE_U2" % (row, col, letter)] + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + params["TASTT_STATE_U2"] = params[getS2StateName(which_layer, s0, s1, s2) + "_U2"] print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) -genTasttLayer(state) + for s0 in range(0,2): + for s1 in range(0,2): + for s2 in range(0,2): + for letter in range(0, CHARS_PER_CELL): + params["TASTT_STATE_U2"] = params[getLetterStateName(which_layer, s0, s1, s2, letter) + "_U2"] + print(replaceMacros(TASTT_LAYER_HEADER_CHILD_STATE, params)) + + params["TASTT_DEFAULT_STATE_U2"] = params["DEFAULT_STATE_U2"] + print(replaceMacros(TASTT_LAYER_FOOTER, params)) + +for i in range(0, NUM_LAYERS): + genTasttLayer(state, i) diff --git a/generate_params.py b/generate_params.py new file mode 100644 index 0000000..665a439 --- /dev/null +++ b/generate_params.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import generate_utils + +PARAM_HEADER = """ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1506855854, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: TaSTT_params + m_EditorClassIdentifier: + parameters: +"""[1:][0:-1] + +INT_PARAM = """ + - name: %PARAM_NAME% + valueType: 0 + saved: 0 + defaultValue: 0 +"""[1:][0:-1] + +BOOL_PARAM = """ + - name: %PARAM_NAME% + valueType: 2 + saved: 0 + defaultValue: 0 +"""[1:][0:-1] + +# We're working with an 84-character board, and each FX layer is responsible +# for 8 of those characters. +params = {} +print(generate_utils.replaceMacros(PARAM_HEADER, params)) + +# Implementation detail. We use this parameter to return from the terminal +# state of the FX layer to the starting state. +params["PARAM_NAME"] = "TaSTT_Dummy" +print(generate_utils.replaceMacros(BOOL_PARAM, params)) + +for i in range(0, generate_utils.NUM_LAYERS): + params["PARAM_NAME"] = generate_utils.getLayerParam(i) + print(generate_utils.replaceMacros(INT_PARAM, params)) + + params["PARAM_NAME"] = generate_utils.getSelectParam(i, 0) + print(generate_utils.replaceMacros(BOOL_PARAM, params)) + + params["PARAM_NAME"] = generate_utils.getSelectParam(i, 1) + print(generate_utils.replaceMacros(BOOL_PARAM, params)) + + params["PARAM_NAME"] = generate_utils.getSelectParam(i, 2) + print(generate_utils.replaceMacros(BOOL_PARAM, params)) + + params["PARAM_NAME"] = generate_utils.getEnableParam(i) + print(generate_utils.replaceMacros(BOOL_PARAM, params)) diff --git a/generate_utils.py b/generate_utils.py new file mode 100644 index 0000000..1abb694 --- /dev/null +++ b/generate_utils.py @@ -0,0 +1,53 @@ +from math import ceil +from math import floor + +def replaceMacros(lines, macro_defs): + for k,v in macro_defs.items(): + lines = lines.replace("%" + k + "%", v) + return lines + +BOARD_ROWS=6 +BOARD_COLS=14 +INDEX_BITS=3 +CHARS_PER_CELL=80 + +NUM_LAYERS=ceil((BOARD_ROWS * BOARD_COLS) / (2**INDEX_BITS)) + +# The bits per layer are: +# 8 bits: letter selection (256 possible letters per slot) +# 3 bits: slot selection (each layer controls 8 slots) +# 1 bit: enable bit (turns layer off while we index to a new slot) +NUM_PARAM_BITS=(NUM_LAYERS * (8 + INDEX_BITS + 1)) + +def getDummyParam(): + return "TaSTT_Dummy" + +# Each layer controls a group of cells. There's only one letter per layer, thus +# this is also the name of the parameter which sets the letter for a layer. +def getLayerParam(which_layer): + return "TaSTT_L%02d" % which_layer + +def getSelectParam(which_layer, which_select): + return "TaSTT_L%02d_S%02d" % (which_layer, which_select) + +def getEnableParam(which_layer): + return "TaSTT_L%02d_E" % which_layer + +def getBoardIndex(which_layer, s0, s1, s2): + # TODO(yum_food) because we divide the board into a multiple of 8 cells, + # some cells describe animations which don't exist. We work around this by + # simply wrapping those animations back to the top of the board, and rely + # on the OSC controller to simply not reference those cells. Clean this up. + return ((s0 * 4 + s1 * 2 + s2) * NUM_LAYERS + which_layer) % (BOARD_ROWS * BOARD_COLS) + +# Mapping from layer to shader param. +def getShaderParam(which_layer, s0, s1, s2): + index = getBoardIndex(which_layer, s0, s1, s2) + + col = index % BOARD_COLS + row = floor(index / BOARD_COLS) + return "_Letter_Row%02d_Col%02d" % (row, col) + +# Returns the path to the animation for the given shader parameter + letter. +def getAnimationPath(shader_param, letter): + return "generated/animations/%s_Letter%02d.anim" % (shader_param, letter) diff --git a/group_names.txt b/group_names.txt deleted file mode 100644 index 0c39082..0000000 --- a/group_names.txt +++ /dev/null @@ -1,24 +0,0 @@ -_Letter_Row00_Col00_03 -_Letter_Row00_Col04_07 -_Letter_Row00_Col08_11 -_Letter_Row00_Col12_13 -_Letter_Row01_Col00_03 -_Letter_Row01_Col04_07 -_Letter_Row01_Col08_11 -_Letter_Row01_Col12_13 -_Letter_Row02_Col00_03 -_Letter_Row02_Col04_07 -_Letter_Row02_Col08_11 -_Letter_Row02_Col12_13 -_Letter_Row03_Col00_03 -_Letter_Row03_Col04_07 -_Letter_Row03_Col08_11 -_Letter_Row03_Col12_13 -_Letter_Row04_Col00_03 -_Letter_Row04_Col04_07 -_Letter_Row04_Col08_11 -_Letter_Row04_Col12_13 -_Letter_Row05_Col00_03 -_Letter_Row05_Col04_07 -_Letter_Row05_Col08_11 -_Letter_Row05_Col12_13 diff --git a/osc_ctrl.py b/osc_ctrl.py index 21386c4..3c19cd9 100644 --- a/osc_ctrl.py +++ b/osc_ctrl.py @@ -6,6 +6,15 @@ import time import fileinput from pythonosc import udp_client +from math import ceil +from math import floor +from generate_utils import getLayerParam +from generate_utils import getSelectParam +from generate_utils import getEnableParam +from generate_utils import getBoardIndex +from generate_utils import NUM_LAYERS +from generate_utils import BOARD_ROWS +from generate_utils import BOARD_COLS def usage(): print("python3 -m pip install python-osc") @@ -18,26 +27,88 @@ args = parser.parse_args() client = udp_client.SimpleUDPClient(args.i, args.p) -seed = random.randrange(3) * 26 -for row in range(0, 6): - addr="/avatar/parameters/TaSTT_Row" - client.send_message(addr, row) - for col in range(0, 14): - addr="/avatar/parameters/TaSTT_Col" - client.send_message(addr, col) +def encodeMessage(msg): + result = [] + for char in msg: + char_int = ord(char) + if char_int >= ord('A') and char_int <= ord('Z'): + result.append(ord(char) - ord('A')) + elif char >= 'a' and char <= 'z': + result.append((ord(char) - ord('a')) + 26) + elif char >= '0' and char <= '9': + result.append((ord(char) - ord('0')) + 52) + elif char == '.': + result.append(62) + elif char == ',': + result.append(63) + elif char == ' ': + result.append(64) + # Pad message with spaces so that it overwrites any leftover text. + result += [65] * (BOARD_ROWS * BOARD_COLS - len(result)) + return result - time.sleep(.5) +# `which_cell` is an integer in the range [0,8). +def sendMessageCell(msg_cell, which_cell): - addr="/avatar/parameters/TaSTT_Active" - client.send_message(addr, True) + s0 = ((floor(which_cell / 4) % 2) == 1) + s1 = ((floor(which_cell / 2) % 2) == 1) + s2 = ((floor(which_cell / 1) % 2) == 1) + + print("Cell s0/s1/s2: {}/{}/{}".format(s0,s1,s2)) + # Seek each layer to the current cell. + for i in range(0, len(msg_cell)): + print("Board index: {}".format(getBoardIndex(i, s0, s1, s2))) + + addr="/avatar/parameters/" + getLayerParam(i) + client.send_message(addr, msg_cell[i]) + + addr="/avatar/parameters/" + getSelectParam(i, 0) + client.send_message(addr, (floor(which_cell / 4) % 2) == 1) - addr="/avatar/parameters/TaSTT_Letter" - client.send_message(addr, (seed + row * 14 + col) % 65) - print("sent {} at {},{}".format((seed + row * 14 + col) % 65, row, col)) + addr="/avatar/parameters/" + getSelectParam(i, 1) + client.send_message(addr, (floor(which_cell / 2) % 2) == 1) - time.sleep(.5) + addr="/avatar/parameters/" + getSelectParam(i, 2) + client.send_message(addr, (which_cell % 2) == 1) + + # Wait for convergence. + time.sleep(0.3) + + # Enable each layer. + # TODO(yum_food) for some reason, if we don't active every layer, the + # desired subset won't reliably fire. Why? + for i in range(0, NUM_LAYERS): + addr="/avatar/parameters/" + getEnableParam(i) + client.send_message(addr, True) - addr="/avatar/parameters/TaSTT_Active" + # Wait for convergence. + time.sleep(0.3) + + # Disable each layer. + for i in range(0, NUM_LAYERS): + addr="/avatar/parameters/" + getEnableParam(i) client.send_message(addr, False) -time.sleep(1000) + # Wait for convergence. + time.sleep(0.3) + +def sendMessage(msg): + # The board is broken down into contiguous collections of characters called + # cells. Each cell contains `NUM_LAYERS` characters. We can update one cell + # every ~1.0 seconds; going faster causes the board to display garbage to + # remote players. + msg = encodeMessage(msg) + + n_cells = ceil(len(msg) / NUM_LAYERS) + for cell in range(0, n_cells): + cell_begin = cell * NUM_LAYERS + cell_end = (cell + 1) * NUM_LAYERS + cell_msg = msg[cell_begin:cell_end] + print("Send cell {}".format(cell)) + sendMessageCell(cell_msg, cell) + +for line in fileinput.input(): + sendMessage(line) + +sendMessage("") + -- cgit v1.2.3