Add Live stage lighting and effects tracks
New data classes (11):
BlinkLight, GlobalFog, Spotlight3d, UVScrollLight,
VolumeLight, LightShafts, Particle, ParticleGroup,
WashLight, Laser + CLAUDE.md
WorkSheet: added 11 new [SerializeField] fields
LiveTimelineControl: added 9 new events + AlterUpdate_SimpleListControl helper
Director: added handlers for all new tracks
Key fixes:
- StageController: register light objects in StageObjectMap (was skipped
with continue), fixes missing stage props like ceiling neonsign
- Spotlight3d handler: use keyData.assetName for StageObjectMap lookup
- BlinkLight: SetActive + child Light color/intensity from timeline data
Coverage (58 songs): BlinkLight 56/58, Effect 55/58, GlobalFog 40/58,
UVScrollLight 32/58, Spotlight3d 30/58
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,16 @@ namespace Gallop.Live.Cutt
|
||||
public event ObjectUpdateInfoDelegate OnUpdateObject;
|
||||
|
||||
public event Action<LiveTimelineEffectData, LiveTimelineKeyEffectData> OnUpdateEffect;
|
||||
public event Action<LiveTimelineGlobalFogData, LiveTimelineKeyGlobalFogData> OnUpdateGlobalFog;
|
||||
public event Action<LiveTimelineSpotlight3dData, LiveTimelineKeySpotlight3dData> OnUpdateSpotlight3d;
|
||||
public event Action<LiveTimelineUVScrollLightData, LiveTimelineKeyUVScrollLightData> OnUpdateUVScrollLight;
|
||||
public event Action<LiveTimelineVolumeLightData, LiveTimelineKeyVolumeLightData> OnUpdateVolumeLight;
|
||||
public event Action<LiveTimelineLightShaftsData, LiveTimelineKeyLightShaftsData> OnUpdateLightShafts;
|
||||
public event Action<LiveTimelineParticleData, LiveTimelineKeyParticleData> OnUpdateParticle;
|
||||
public event Action<LiveTimelineParticleGroupData, LiveTimelineKeyParticleGroupData> OnUpdateParticleGroup;
|
||||
public event Action<LiveTimelineWashLightData, LiveTimelineKeyWashLightData> OnUpdateWashLight;
|
||||
public event Action<LiveTimelineLaserData, LiveTimelineKeyLaserData> OnUpdateLaser;
|
||||
public event Action<LiveTimelineBlinkLightData, LiveTimelineKeyBlinkLightData> OnUpdateBlinkLight;
|
||||
|
||||
private static Func<LiveTimelineKeyCameraPositionData, LiveTimelineControl, FindTimelineConfig, Vector3> fnGetCameraPosValue = GetCameraPosValue;
|
||||
|
||||
@@ -344,6 +354,16 @@ namespace Gallop.Live.Cutt
|
||||
AlterUpdate_TransformControl(workSheet, _currentFrame);
|
||||
AlterUpdate_ObjectControl(workSheet, _currentFrame);
|
||||
AlterUpdate_EffectControl(workSheet, _currentFrame);
|
||||
AlterUpdate_GlobalFogControl(workSheet, _currentFrame);
|
||||
AlterUpdate_Spotlight3dControl(workSheet, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.uvScrollLightList, d => d.keys, OnUpdateUVScrollLight, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.volumeLightKeys, d => d.keys, OnUpdateVolumeLight, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.lightShaftsKeysLine, d => d.keys, OnUpdateLightShafts, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.particleList, d => d.keys, OnUpdateParticle, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.particleGroupList, d => d.keys, OnUpdateParticleGroup, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.WashLightList, d => d.keys, OnUpdateWashLight, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.laserList, d => d.keys, OnUpdateLaser, _currentFrame);
|
||||
AlterUpdate_SimpleListControl(workSheet.blinkLightList, d => d.keys, OnUpdateBlinkLight, _currentFrame);
|
||||
|
||||
_isNowAlterUpdate = false;
|
||||
|
||||
@@ -1842,6 +1862,49 @@ namespace Gallop.Live.Cutt
|
||||
}
|
||||
}
|
||||
|
||||
private void AlterUpdate_SimpleListControl<TData, TKey>(
|
||||
List<TData> list,
|
||||
System.Func<TData, ILiveTimelineKeyDataList> getKeys,
|
||||
Action<TData, TKey> onUpdate,
|
||||
float currentFrame) where TKey : LiveTimelineKey
|
||||
{
|
||||
if (list == null || onUpdate == null) return;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
var keys = getKeys(entry);
|
||||
if (keys == null || keys.HasAttribute(LiveTimelineKeyDataListAttr.Disable) || !keys.EnablePlayModeTimeline(_playMode)) continue;
|
||||
FindTimelineKey(out var curKey, out var _, keys, currentFrame);
|
||||
if (curKey == null) continue;
|
||||
onUpdate.Invoke(entry, curKey as TKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void AlterUpdate_GlobalFogControl(LiveTimelineWorkSheet sheet, float currentFrame)
|
||||
{
|
||||
if (sheet.globalFogDataLists == null || OnUpdateGlobalFog == null) return;
|
||||
foreach (var fogData in sheet.globalFogDataLists)
|
||||
{
|
||||
var keys = fogData.keys;
|
||||
if (keys == null || keys.HasAttribute(LiveTimelineKeyDataListAttr.Disable) || !keys.EnablePlayModeTimeline(_playMode)) continue;
|
||||
FindTimelineKey(out var curKey, out var _, keys, currentFrame);
|
||||
if (curKey == null) continue;
|
||||
OnUpdateGlobalFog.Invoke(fogData, curKey as LiveTimelineKeyGlobalFogData);
|
||||
}
|
||||
}
|
||||
|
||||
private void AlterUpdate_Spotlight3dControl(LiveTimelineWorkSheet sheet, float currentFrame)
|
||||
{
|
||||
if (sheet.spotlight3dList == null || OnUpdateSpotlight3d == null) return;
|
||||
foreach (var spotData in sheet.spotlight3dList)
|
||||
{
|
||||
var keys = spotData.keys;
|
||||
if (keys == null || keys.HasAttribute(LiveTimelineKeyDataListAttr.Disable) || !keys.EnablePlayModeTimeline(_playMode)) continue;
|
||||
FindTimelineKey(out var curKey, out var _, keys, currentFrame);
|
||||
if (curKey == null) continue;
|
||||
OnUpdateSpotlight3d.Invoke(spotData, curKey as LiveTimelineKeySpotlight3dData);
|
||||
}
|
||||
}
|
||||
|
||||
private static float LerpWithoutClamp(float a, float b, float t)
|
||||
{
|
||||
return a + (b - a) * t;
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyBlinkLightData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public int LightBlendMode;
|
||||
public Color[] color0Array;
|
||||
public Color[] color1Array;
|
||||
public float[] powerArray;
|
||||
public int[] isReverseHueArray;
|
||||
public int[] CmnColorType0Array;
|
||||
public int[] CmnColorType1Array;
|
||||
public int[] CharacterIndex0Array;
|
||||
public int[] CharacterIndex1Array;
|
||||
public int[] IsColorBlend0Array;
|
||||
public int[] IsColorBlend1Array;
|
||||
public float[] ColorBlendRate0Array;
|
||||
public float[] ColorBlendRate1Array;
|
||||
public Color[] AltCharaColor0Array;
|
||||
public Color[] AltCharaColor1Array;
|
||||
public int pattern;
|
||||
public int colorType;
|
||||
public float powerMin;
|
||||
public float powerMax;
|
||||
public int loopCount;
|
||||
public float waitTime;
|
||||
public float turnOnTime;
|
||||
public float turnOffTime;
|
||||
public float keepTime;
|
||||
public float intervalTime;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyBlinkLightDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyBlinkLightData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineBlinkLightData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "BlinkLight";
|
||||
public LiveTimelineKeyBlinkLightDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27698a601219c0c429243d86175f2d93
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyGlobalFogData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public bool isDistance;
|
||||
public float startDistance;
|
||||
public bool isHeight;
|
||||
public float height;
|
||||
public float heightDensity;
|
||||
public Color color;
|
||||
public int fogMode;
|
||||
public float expDensity;
|
||||
public float start;
|
||||
public float end;
|
||||
public bool useRadialDistance;
|
||||
public string BlinkLightName;
|
||||
public int BlinkLightNameHash;
|
||||
public int BlinkLightContainerIndex;
|
||||
public float BlinkLightBrightnessPower;
|
||||
public bool IsAdjustedBlinkLightColor;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyGlobalFogDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyGlobalFogData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineGlobalFogData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "GlobalFog";
|
||||
public LiveTimelineKeyGlobalFogDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e2a3321bb359c40b8b3c415e109fd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyLaserData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public Vector3 objectPosition;
|
||||
public Vector3 objectRotate;
|
||||
public Vector3 objectScale;
|
||||
public int formation;
|
||||
public Vector3 rotate;
|
||||
public float degRootYaw;
|
||||
public float degLaserPitch;
|
||||
public float posInterval;
|
||||
public bool blink;
|
||||
public float blinkPeriod;
|
||||
public float RaycastDistance;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyLaserDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyLaserData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineLaserData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "Laser";
|
||||
public LiveTimelineKeyLaserDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d017b2b13aaf198478d9d166f535042e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyLightShaftsData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public bool enabled;
|
||||
public Vector4 speed;
|
||||
public Vector4 angle;
|
||||
public Vector4 offset;
|
||||
public Vector4 alpha;
|
||||
public Vector4 alpha2;
|
||||
public Vector4 maskAlpha;
|
||||
public float maskAnimeTime;
|
||||
public Vector2 maskAlphaRange;
|
||||
public float scale;
|
||||
public bool _isAdjustScale;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyLightShaftsDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyLightShaftsData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineLightShaftsData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "LightShafts";
|
||||
public LiveTimelineKeyLightShaftsDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2defe0a911be96428d8d214e9d43402
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyParticleData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public float emissionRate;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyParticleDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyParticleData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineParticleData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "Particle";
|
||||
public LiveTimelineKeyParticleDataList keys;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyParticleGroupData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public float FlickerLightRate;
|
||||
public float FlickerDarkRate;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyParticleGroupDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyParticleGroupData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineParticleGroupData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "ParticleGroup";
|
||||
public LiveTimelineKeyParticleGroupDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93810b8781b1ba3488eb3dfccea5a918
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeySpotlight3dData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public bool isActive;
|
||||
public Color color;
|
||||
public float colorPower;
|
||||
public float localHeight;
|
||||
public Vector3 position;
|
||||
public Vector3 rotation;
|
||||
public Vector3 scale;
|
||||
public Vector3 characterPosition;
|
||||
public int targetCameraType;
|
||||
public int targetCameraIndex;
|
||||
public string assetName;
|
||||
public int characterIndex;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeySpotlight3dDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeySpotlight3dData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineSpotlight3dData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "Spotlight3d";
|
||||
public LiveTimelineKeySpotlight3dDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd8302e2eac444e4ba0cba9ccc97026c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyUVScrollLightData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public Color mulColor0;
|
||||
public Color mulColor1;
|
||||
public float colorPower;
|
||||
public float scrollOffsetX;
|
||||
public float scrollOffsetY;
|
||||
public float scrollSpeedX;
|
||||
public float scrollSpeedY;
|
||||
public int ColorType0;
|
||||
public int ColorType1;
|
||||
public int CharacterIndex0;
|
||||
public int CharacterIndex1;
|
||||
public bool IsColorBlend0;
|
||||
public bool IsColorBlend1;
|
||||
public float ColorBlendRate0;
|
||||
public float ColorBlendRate1;
|
||||
public Color AltCharaColor0;
|
||||
public Color AltCharaColor1;
|
||||
public int loopType;
|
||||
public int loopCount;
|
||||
public int loopExecutedCount;
|
||||
public int loopIntervalFrame;
|
||||
public bool isPasteLoopUnit;
|
||||
public bool isChangeLoopInterpolate;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyUVScrollLightDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyUVScrollLightData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineUVScrollLightData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "UVScrollLight";
|
||||
public LiveTimelineKeyUVScrollLightDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 600b9a8f3fac16a44b25340cb3abd732
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyVolumeLightData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public Vector3 sunPosition;
|
||||
public Color color1;
|
||||
public float power;
|
||||
public float komorebi;
|
||||
public float blurRadius;
|
||||
public float ColorRate;
|
||||
public float ScreenColorPower;
|
||||
public float EffectColorPower;
|
||||
public bool enable;
|
||||
public bool isEnabledBorderClear;
|
||||
public string BlinkLightName;
|
||||
public int BlinkLightNameHash;
|
||||
public int BlinkLightContainerIndex;
|
||||
public float BlinkLightBrightnessPower;
|
||||
public bool IsAdjustedBlinkLightColor;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyVolumeLightDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyVolumeLightData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineVolumeLightData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "VolumeLight";
|
||||
public LiveTimelineKeyVolumeLightDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cde7635e3754d34b8b642cd34f5cb73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gallop.Live.Cutt
|
||||
{
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyWashLightData : LiveTimelineKeyWithInterpolate
|
||||
{
|
||||
public float RaycastDistance;
|
||||
public float CameraProjectionSide;
|
||||
public float CameraProjectionColorPower;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineKeyWashLightDataList : LiveTimelineKeyDataListTemplate<LiveTimelineKeyWashLightData>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class LiveTimelineWashLightData : ILiveTimelineGroupDataWithName
|
||||
{
|
||||
private const string default_name = "WashLight";
|
||||
public LiveTimelineKeyWashLightDataList keys;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 624bbfba74d8dff44a7c970f35bb63a5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -937,6 +937,16 @@ namespace Gallop.Live.Cutt
|
||||
[SerializeField] public List<LiveTimelineTransformData> transformList;
|
||||
[SerializeField] public List<LiveTimelineObjectData> objectList;
|
||||
[SerializeField] public List<LiveTimelineEffectData> effectList;
|
||||
[SerializeField] public List<LiveTimelineGlobalFogData> globalFogDataLists;
|
||||
[SerializeField] public List<LiveTimelineSpotlight3dData> spotlight3dList;
|
||||
[SerializeField] public List<LiveTimelineUVScrollLightData> uvScrollLightList;
|
||||
[SerializeField] public List<LiveTimelineVolumeLightData> volumeLightKeys;
|
||||
[SerializeField] public List<LiveTimelineLightShaftsData> lightShaftsKeysLine;
|
||||
[SerializeField] public List<LiveTimelineParticleData> particleList;
|
||||
[SerializeField] public List<LiveTimelineParticleGroupData> particleGroupList;
|
||||
[SerializeField] public List<LiveTimelineWashLightData> WashLightList;
|
||||
[SerializeField] public List<LiveTimelineLaserData> laserList;
|
||||
[SerializeField] public List<LiveTimelineBlinkLightData> blinkLightList;
|
||||
|
||||
/*
|
||||
//���ڿ��Ե���AB���ˣ���Ȼ���淢��ûʲô��...˵����ʲôʱ�����õ�
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Gallop.Live
|
||||
// effect track: maps effectList entry -> (last key frame, active instance)
|
||||
private Dictionary<LiveTimelineEffectData, (int frame, GameObject instance)> _activeEffects
|
||||
= new Dictionary<LiveTimelineEffectData, (int, GameObject)>();
|
||||
|
||||
public UmaViewerAudio.CuteAudioSource liveMusic = new UmaViewerAudio.CuteAudioSource();
|
||||
|
||||
public PartEntry partInfo;
|
||||
@@ -296,6 +297,16 @@ namespace Gallop.Live
|
||||
};
|
||||
|
||||
_liveTimelineControl.OnUpdateEffect += OnEffectUpdate;
|
||||
_liveTimelineControl.OnUpdateGlobalFog += OnGlobalFogUpdate;
|
||||
_liveTimelineControl.OnUpdateSpotlight3d += OnSpotlight3dUpdate;
|
||||
_liveTimelineControl.OnUpdateUVScrollLight += OnUVScrollLightUpdate;
|
||||
_liveTimelineControl.OnUpdateVolumeLight += OnVolumeLightUpdate;
|
||||
_liveTimelineControl.OnUpdateLightShafts += OnLightShaftsUpdate;
|
||||
_liveTimelineControl.OnUpdateParticle += OnParticleUpdate;
|
||||
_liveTimelineControl.OnUpdateParticleGroup += OnParticleGroupUpdate;
|
||||
_liveTimelineControl.OnUpdateWashLight += OnWashLightUpdate;
|
||||
_liveTimelineControl.OnUpdateLaser += OnLaserUpdate;
|
||||
_liveTimelineControl.OnUpdateBlinkLight += OnBlinkLightUpdate;
|
||||
}
|
||||
|
||||
private void OnEffectUpdate(LiveTimelineEffectData effectData, LiveTimelineKeyEffectData keyData)
|
||||
@@ -366,6 +377,128 @@ namespace Gallop.Live
|
||||
t.localScale = keyData.offsetScale;
|
||||
}
|
||||
|
||||
private void OnGlobalFogUpdate(LiveTimelineGlobalFogData fogData, LiveTimelineKeyGlobalFogData keyData)
|
||||
{
|
||||
if (keyData == null) return;
|
||||
RenderSettings.fog = keyData.isDistance || keyData.isHeight || keyData.fogMode != 0;
|
||||
RenderSettings.fogColor = keyData.color;
|
||||
RenderSettings.fogMode = (FogMode)keyData.fogMode;
|
||||
RenderSettings.fogDensity = keyData.expDensity;
|
||||
RenderSettings.fogStartDistance = keyData.start;
|
||||
RenderSettings.fogEndDistance = keyData.end;
|
||||
}
|
||||
|
||||
private void OnSpotlight3dUpdate(LiveTimelineSpotlight3dData spotData, LiveTimelineKeySpotlight3dData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
|
||||
// spotlight3d objects are part of the stage prefab — look up by assetName in StageObjectMap
|
||||
if (!_stageController.StageObjectMap.TryGetValue(keyData.assetName, out var go)) return;
|
||||
|
||||
go.SetActive(keyData.isActive);
|
||||
if (!keyData.isActive) return;
|
||||
|
||||
Vector3 basePos = Vector3.zero;
|
||||
if (keyData.characterIndex >= 0 && keyData.characterIndex < CharaContainerScript.Count)
|
||||
basePos = CharaContainerScript[keyData.characterIndex].transform.position;
|
||||
|
||||
go.transform.position = basePos + keyData.position;
|
||||
go.transform.eulerAngles = keyData.rotation;
|
||||
go.transform.localScale = keyData.scale;
|
||||
}
|
||||
|
||||
private void OnUVScrollLightUpdate(LiveTimelineUVScrollLightData data, LiveTimelineKeyUVScrollLightData keyData)
|
||||
{
|
||||
if (keyData == null) return;
|
||||
// find renderers in stage with matching material name
|
||||
if (_stageController == null) return;
|
||||
foreach (var r in _stageController.GetComponentsInChildren<Renderer>())
|
||||
{
|
||||
foreach (var mat in r.materials)
|
||||
{
|
||||
string matName = mat.name.Replace(" (Instance)", "");
|
||||
if (matName != data.name) continue;
|
||||
mat.SetTextureOffset("_MainTex", new Vector2(keyData.scrollOffsetX, keyData.scrollOffsetY));
|
||||
mat.SetTextureScale("_MainTex", new Vector2(keyData.scrollSpeedX, keyData.scrollSpeedY));
|
||||
mat.SetColor("_Color", keyData.mulColor0 * keyData.colorPower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBlinkLightUpdate(LiveTimelineBlinkLightData data, LiveTimelineKeyBlinkLightData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
if (!_stageController.StageObjectMap.TryGetValue(data.name, out var go)) return;
|
||||
|
||||
go.SetActive(true);
|
||||
|
||||
// Apply colors and power to child Light components
|
||||
var lights = go.GetComponentsInChildren<Light>(true);
|
||||
if (lights.Length == 0) return;
|
||||
|
||||
for (int i = 0; i < lights.Length; i++)
|
||||
{
|
||||
int idx = i < keyData.powerArray?.Length ? i : 0;
|
||||
float power = keyData.powerArray != null && keyData.powerArray.Length > idx
|
||||
? keyData.powerArray[idx] : 1f;
|
||||
Color col = keyData.color0Array != null && keyData.color0Array.Length > idx
|
||||
? keyData.color0Array[idx] : Color.white;
|
||||
|
||||
lights[i].color = col;
|
||||
lights[i].intensity = power;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWashLightUpdate(LiveTimelineWashLightData data, LiveTimelineKeyWashLightData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
if (!_stageController.StageObjectMap.TryGetValue(data.name, out var go)) return;
|
||||
go.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnLaserUpdate(LiveTimelineLaserData data, LiveTimelineKeyLaserData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
if (!_stageController.StageObjectMap.TryGetValue(data.name, out var go)) return;
|
||||
go.SetActive(true);
|
||||
go.transform.localPosition = keyData.objectPosition;
|
||||
go.transform.localEulerAngles = keyData.objectRotate;
|
||||
go.transform.localScale = keyData.objectScale;
|
||||
}
|
||||
|
||||
private void OnVolumeLightUpdate(LiveTimelineVolumeLightData data, LiveTimelineKeyVolumeLightData keyData)
|
||||
{
|
||||
// SunShafts component not present in this build — data deserialized only
|
||||
}
|
||||
|
||||
private void OnLightShaftsUpdate(LiveTimelineLightShaftsData data, LiveTimelineKeyLightShaftsData keyData)
|
||||
{
|
||||
// LightShaftsController component not present in this build — data deserialized only
|
||||
}
|
||||
|
||||
private void OnParticleUpdate(LiveTimelineParticleData data, LiveTimelineKeyParticleData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
foreach (var ps in _stageController.GetComponentsInChildren<ParticleSystem>())
|
||||
{
|
||||
if (ps.gameObject.name != data.name) continue;
|
||||
var emission = ps.emission;
|
||||
emission.rateOverTime = keyData.emissionRate;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnParticleGroupUpdate(LiveTimelineParticleGroupData data, LiveTimelineKeyParticleGroupData keyData)
|
||||
{
|
||||
if (keyData == null || _stageController == null) return;
|
||||
foreach (var ps in _stageController.GetComponentsInChildren<ParticleSystem>())
|
||||
{
|
||||
if (ps.gameObject.name != data.name) continue;
|
||||
var emission = ps.emission;
|
||||
// FlickerLightRate/DarkRate: modulate emission rate between dark and light values
|
||||
emission.rateOverTime = keyData.FlickerLightRate;
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeCamera()
|
||||
{
|
||||
if (_cameraObjects == null)
|
||||
|
||||
@@ -52,14 +52,7 @@ namespace Gallop.Live
|
||||
if (!StageObjectMap.ContainsKey(child.name))
|
||||
{
|
||||
if (child.name.Contains("light"))
|
||||
{
|
||||
// Since the parsing of light material keyframes has been implemented
|
||||
// Directly displaying the light will block the view
|
||||
// Therefore, the light's GameObject is hidden here first
|
||||
// TODO: Remove this after implementing light parsing
|
||||
child.gameObject.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
child.gameObject.SetActive(false); // hidden by default, handlers activate as needed
|
||||
var tmp_name = child.name.Replace("(Clone)", "");
|
||||
StageObjectMap.Add(tmp_name, child.gameObject);
|
||||
StageParentMap.TryAdd(tmp_name, child.gameObject.transform.parent);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
UmaViewer is a Unity application (2022.3.62f1) that loads and displays assets from Uma Musume: Pretty Derby. It reads encrypted asset bundles directly from the game installation without modifying game files.
|
||||
|
||||
## Development
|
||||
|
||||
**Open the project:** Unity Hub → Add → `C:\Users\riten\Desktop\UmaBuild`
|
||||
**Run:** Open `Assets/Scenes/Version2` scene → Play in Unity Editor
|
||||
**Build:** File → Build Settings → PC Standalone → Build
|
||||
|
||||
No CLI build commands — Unity Editor is required.
|
||||
|
||||
## Game Data & Asset Pipeline
|
||||
|
||||
Game assets are encrypted. Key files:
|
||||
- `meta` (SQLite-MC ChaCha20 encrypted) — maps bundle names → hash filenames in `dat/`
|
||||
- `dat/{2-char-prefix}/{hash}` — encrypted asset bundles, each with a per-bundle XOR key from meta
|
||||
|
||||
**Bundle decryption** (`UmaAssetBundleStream.cs`): header (first 256 bytes) is plain; bytes ≥256 are XOR'd with `FKey = ABKey[i] XOR bundleKey_bytes[j]`.
|
||||
|
||||
**meta DB decryption**: `UmaDatabaseController.ReadMetaFromEncryptedDb()` uses `sqlite3mc_x64.dll` with cipher=3 (ChaCha20). Final key = `DBKey[i] XOR DBBaseKey[i % 13]`. A decrypted copy lives at `C:\Users\riten\Desktop\UmaCrack\meta_plain.db`.
|
||||
|
||||
**Asset bundle paths** (key formats):
|
||||
- Live cutt timelines: `cutt/cutt_son{music_id}/cutt_son{music_id}`
|
||||
- Live effect prefabs: `3d/effect/live/pfb_{effectName}`
|
||||
- Stage prefabs: `3d/env/live/live{bgId}/pfb_env_live{bgId}_controller000`
|
||||
|
||||
**Python tools** (`C:\Users\riten\Desktop\UmaCrack\`):
|
||||
- `dump_meta_cutt.py` — decrypts meta DB → `meta_plain.db`, run with Windows Python
|
||||
- `read_cutt_effect.py` — loads cutt bundles via UnityPy, dumps WorkSheet field TypeTrees
|
||||
|
||||
## Live Timeline Architecture
|
||||
|
||||
The Live playback system is in `Assets/Scripts/umamusume/Gallop/Live/`:
|
||||
|
||||
```
|
||||
Director.cs ← singleton, wires everything together
|
||||
Cutt/
|
||||
LiveTimelineControl.cs ← dispatches timeline events each frame (~1900 lines)
|
||||
LiveTimelineWorkSheet.cs ← all track data fields (ScriptableObject)
|
||||
LiveTimelineDataList/ ← one .cs per track type
|
||||
UpdateInfo/ ← structs passed to event handlers
|
||||
StageController.cs ← manages stage GameObjects, StageObjectMap
|
||||
```
|
||||
|
||||
**Track implementation pattern** (repeat for each new track):
|
||||
1. Add data class in `LiveTimelineDataList/` (extend `LiveTimelineKeyWithInterpolate` for key, add group wrapper implementing `ILiveTimelineGroupDataWithName`)
|
||||
2. Add `[SerializeField] public List<...> trackList;` to `LiveTimelineWorkSheet`
|
||||
3. Add `public event Action<TData, TKey> OnUpdateXxx;` in `LiveTimelineControl`
|
||||
4. Call `AlterUpdate_SimpleListControl(workSheet.trackList, d => d.keys, OnUpdateXxx, _currentFrame)` in `AlterLateUpdate()`
|
||||
5. Subscribe `_liveTimelineControl.OnUpdateXxx += handler` in `Director.InitializeTimeline()`
|
||||
|
||||
**Important:** `LiveTimelineKeyWithInterpolate` already declares `frame`, `attribute`, `interpolateType`, `curve`, `easingType` — do NOT redeclare these in subclasses.
|
||||
|
||||
**StageObjectMap:** Stage child GameObjects are indexed by name. Objects with "light" in their name start `SetActive(false)` but ARE registered — handlers call `SetActive(true)` as needed.
|
||||
|
||||
## Currently Implemented Tracks
|
||||
|
||||
| Track | Data class | Notes |
|
||||
|-------|-----------|-------|
|
||||
| Camera (pos/lookat/fov/roll/switcher) | existing | fully working |
|
||||
| CharaMotionSequence | existing | |
|
||||
| Facial / LipSync / FormationOffset | existing | |
|
||||
| GlobalLight (48) | existing | sets rim light shader props on characters |
|
||||
| BgColor1/2 | existing | sets toon shader color props |
|
||||
| Transform / Object | existing | handled by `StageController.cs` |
|
||||
| Effect (60) | `LiveTimelineEffectData` | loads prefab from `3d/effect/live/pfb_{name}` |
|
||||
| GlobalFog (49) | `LiveTimelineGlobalFogData` | sets `RenderSettings.fog*` |
|
||||
| Spotlight3d (68) | `LiveTimelineSpotlight3dData` | looks up `keyData.assetName` in StageObjectMap |
|
||||
| UVScrollLight (46) | `LiveTimelineUVScrollLightData` | sets texture UV on stage materials |
|
||||
| VolumeLight (37) | `LiveTimelineVolumeLightData` | data deserialized, no visual (component absent) |
|
||||
| LightShafts (50) | `LiveTimelineLightShaftsData` | data deserialized, no visual (component absent) |
|
||||
| Particle (41) | `LiveTimelineParticleData` | sets ParticleSystem.emission.rateOverTime |
|
||||
| ParticleGroup (42) | `LiveTimelineParticleGroupData` | sets FlickerLightRate |
|
||||
|
||||
## Track Coverage (from 58-song scan)
|
||||
|
||||
High priority missing (have data in live bundles):
|
||||
- `blinkLightList` — 56/58 songs, controls named light prefabs in stage
|
||||
- `WashLightList` — 5/58 songs
|
||||
- `laserList` — 6/58 songs
|
||||
|
||||
Field definitions are obtained by running `read_cutt_effect.py` to dump the WorkSheet TypeTree from a cutt bundle.
|
||||
Reference in New Issue
Block a user