HeavenStudioPlus/Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs
AstrlJelly caf124a8cd
Advanced Blocks (#720)
* play sfx and play animation blocks

i also changed prescheduleFunction to preFunction, and removed the unused preFunction argument in GameAction
i can revert this if need be but it just seemed vestigial

* count in rework + preloading, multisound addition

multisound was using an array that was converted to a list..?
very silly when you consider it's a list first so sometimes it's list -> array -> list lol

new Count-In and Play SFX block preloads sfx now!! epic.

* prefab-ify event properties, Button EntityType

* things are very nearly working!

however i just hit an insane hurdle. how do i modify a dropdown while still being able to access the index/int value of that param directly. UGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

* okay it's WORKING now

i just need to do some better dropdown stuff

* ITS WORKING ITS WORKING ITS WORKING

arbitrary animations, now accessible to those without prefab knowledge! and it's piss easy to use!!

* about to make a struct + class, tooltip improvements

gonna make the struct define it, then the class will actually be the dropdown
this is gonna make things so so so so much easier to comprehend

* finishing up, probably one more commit after this

* split up Dropdown into Dropdown and DropdownObj, which basically fixed all of my problems lol
* fixed a count bug
* added param tooltip toggle

* grah it's ALMOST DONE

* it's 99.9% finished.

just some touch ups, i don't think i even know of any bugs

* alright, looks like that's all the bugs gone

* EVERYTHING IS FINISHED!!
2024-02-26 01:46:23 +00:00

553 lines
No EOL
18 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using Jukebox;
using TMPro;
using System.Linq;
using System.Collections.Generic;
namespace HeavenStudio.Editor.Track
{
public class TimelineEventObj : MonoBehaviour
{
public bool interacting;
private Vector3 lastPos;
public Vector2 moveStartPos;
private RectTransform rectTransform;
[Header("Components")]
[SerializeField] private RectTransform PosPreview;
[SerializeField] private RectTransform PosPreviewRef;
[SerializeField] public Image Icon;
[SerializeField] private Image selectedImage;
[SerializeField] public TMP_Text eventLabel;
[SerializeField] private Image resizeGraphic;
[SerializeField] private RectTransform leftDrag;
[SerializeField] private RectTransform rightDrag;
[SerializeField] private Image outline;
[SerializeField] private Image hasPropertiesIcon;
[SerializeField] private RectTransform visibleRegion;
// private GameObject moveTemp;
[Header("Properties")]
public RiqEntity entity;
public float length;
private bool lastVisible;
public bool selected;
public bool mouseHovering;
public bool resizable;
public bool moving;
public bool wasDuplicated;
public bool resizing => resizingLeft || resizingRight;
private bool resizingLeft;
private bool resizingRight;
private bool inResizeRegion;
private float resizingLeftBL;
private double lastResizeBeat = 0;
private float lastResizeLength = 0;
public bool isCreating;
private bool altWhenClicked = false;
private bool dragging = false;
private double initMoveX = 0;
private float initMoveY = 0;
private bool movedEntity = false;
private double lastBeat = 0;
private int lastLayer = 0;
private int lastSiblingIndex;
private bool changedSiblingIndex;
public float zPriority { get; private set; }
// Difference between mouseHovering is this is regardless if the user can see it.
private bool mouseOver;
private float clickTimer = 0.0f;
[Header("Colors")]
public Color NormalCol;
public void SetMarkerInfo()
{
moveStartPos = transform.localPosition;
rectTransform = GetComponent<RectTransform>();
var eventName = entity.datamodel;
string[] split = eventName.Split('/');
var action = EventCaller.instance.GetGameAction(split[0], split[1]);
if (split[1] == "switchGame")
Icon.sprite = Editor.GameIcon(split[2]);
else
Icon.sprite = Editor.GameIcon(split[0]);
if (action != null)
{
this.resizable = action.resizable;
if (action.resizable == false)
{
rectTransform.sizeDelta = new Vector2(action.defaultLength * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
this.length = action.defaultLength;
}
else
{
if (entity != null && action.defaultLength != entity.length)
{
rectTransform.sizeDelta = new Vector2(entity.length * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
}
else
{
rectTransform.sizeDelta = new Vector2(action.defaultLength * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
}
}
}
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, (int)-entity["track"] * Timeline.instance.LayerHeight());
resizeGraphic.gameObject.SetActive(resizable);
eventLabel.text = action.displayName;
hasPropertiesIcon.enabled = action.actionName != "switchGame" && action.parameters != null && action.parameters.Count > 0;
SetColor((int)entity["track"]);
SetWidthHeight();
selectedImage.gameObject.SetActive(false);
lastBeat = entity.beat;
initMoveX = 0.0f;
initMoveY = 0.0f;
lastResizeBeat = 0;
lastResizeLength = 0;
}
public void SetEntity(RiqEntity entity)
{
this.entity = entity;
}
public void Update()
{
clickTimer += Time.deltaTime;
}
public void UpdateMarker()
{
mouseOver = Timeline.instance.timelineState.selected && Timeline.instance.MouseInTimeline &&
HeavenStudio.Util.MathUtils.IsBetween(Timeline.instance.MousePos2Beat, (float)entity.beat, (float)entity.beat + entity.length) &&
Timeline.instance.MousePos2Layer == (int)entity["track"];
eventLabel.overflowMode = (mouseHovering || moving || resizing || inResizeRegion) ? TextOverflowModes.Overflow : TextOverflowModes.Ellipsis;
if (selected)
{
if (TimelineBlockManager.Instance.MovingAnyEvents)
{
outline.color = Color.magenta;
SetColor((int)entity["track"]);
}
else
outline.color = Color.cyan;
}
else
{
outline.color = new Color32(0, 0, 0, 51);
}
if (Conductor.instance.NotStopped())
{
if (moving)
{
moving = false;
}
if (selected)
{
Selections.instance.Deselect(this);
outline.color = new Color32(0, 0, 0, 51);
}
return;
}
if (resizingRight)
{
if (moving) moving = false;
entity.length = Mathf.Max(Timeline.instance.MousePos2BeatSnap - (float)entity.beat, Timeline.instance.snapInterval);
SetWidthHeight();
}
else if (resizingLeft)
{
if (moving) moving = false;
entity.beat = Mathf.Min(Timeline.instance.MousePos2BeatSnap, resizingLeftBL - Timeline.instance.snapInterval);
entity.length = Mathf.Max(resizingLeftBL - (float)entity.beat, Timeline.instance.snapInterval);
SetWidthHeight();
}
else
{
if (Input.GetMouseButtonUp(0))
{
if (moving)
{
moving = false;
if (!isCreating && movedEntity)
{
// NOTE (PELLY): Replace with arrays soon
List<double> lastBeats = new();
List<int> lastLayers = new();
foreach (var marker in Selections.instance.eventsSelected)
{
var entity = marker.entity;
lastBeats.Add(marker.entity.beat);
lastLayers.Add((int)marker.entity["track"]);
entity.beat = marker.lastBeat;
entity["track"] = marker.lastLayer;
}
CommandManager.Instance.AddCommand(new Commands.Move(Selections.instance.eventsSelected.Select(c => c.entity).ToList(), lastBeats, lastLayers));
}
isCreating = false;
GameManager.instance.SortEventsList();
TimelineBlockManager.Instance.SortMarkers();
}
altWhenClicked = false;
dragging = false;
}
if (moving)
{
foreach (var marker in Selections.instance.eventsSelected)
{
marker.entity.beat = System.Math.Max(Timeline.instance.MousePos2BeatSnap - marker.initMoveX, 0);
marker.entity["track"] = Mathf.Clamp(Timeline.instance.MousePos2Layer - marker.initMoveY, 0, Timeline.instance.LayerCount - 1);
marker.SetColor((int)entity["track"]);
marker.SetWidthHeight();
}
}
}
if (Input.GetMouseButtonUp(0))
{
OnLeftUp();
OnRightUp();
}
// should consider adding this someday
// else if (moving && selected || mouseHovering && selected)
// {
// Cursor.SetCursor(Resources.Load<Texture2D>("Cursors/move"), new Vector2(8, 8), CursorMode.Auto);
// }
zPriority = entity.length;
if (selected)
zPriority += 10000;
}
public void LateUpdate()
{
rectTransform.anchoredPosition = new Vector2((float)entity.beat * Timeline.instance.PixelsPerBeat, -(int)entity["track"] * Timeline.instance.LayerHeight());
SetWidthHeight();
var followXL = (Timeline.instance.leftSide - (float)entity.beat) * Timeline.instance.PixelsPerBeat;
visibleRegion.offsetMin = new Vector2(
Mathf.Clamp(followXL - 2, 0, (entity.length * Timeline.instance.PixelsPerBeat) - Timeline.instance.LayerHeight()),
visibleRegion.offsetMin.y);
var followXR = (Timeline.instance.rightSide - ((float)entity.beat + entity.length)) * Timeline.instance.PixelsPerBeat;
visibleRegion.offsetMax = new Vector2(
Mathf.Clamp(followXR, -(entity.length * Timeline.instance.PixelsPerBeat) + 8, 0),
visibleRegion.offsetMax.y);
}
public void BeginMoving(bool setMovedEntity = true)
{
moving = true;
foreach (var marker in Selections.instance.eventsSelected)
{
if (setMovedEntity) marker.movedEntity = true;
marker.lastBeat = marker.entity.beat;
marker.lastLayer = (int)marker.entity["track"];
marker.initMoveX = Timeline.instance.MousePos2BeatSnap - marker.entity.beat;
marker.initMoveY = Timeline.instance.MousePos2Layer - (int)marker.entity["track"];
}
}
#region ClickEvents
public void HoverEnter()
{
if (!TimelineBlockManager.Instance.MovingAnyEvents)
{
lastSiblingIndex = gameObject.transform.GetSiblingIndex();
gameObject.transform.SetAsLastSibling();
changedSiblingIndex = true;
}
else
changedSiblingIndex = false;
mouseHovering = true;
if (!selected && !TimelineBlockManager.Instance.MovingAnyEvents) selectedImage.gameObject.SetActive(true);
}
public void HoverExit()
{
if (changedSiblingIndex)
gameObject.transform.SetSiblingIndex(lastSiblingIndex);
mouseHovering = false;
selectedImage.gameObject.SetActive(false);
}
public void OnDragMain()
{
if (Conductor.instance.NotStopped()) return;
if (Input.GetMouseButton(1) || Input.GetMouseButton(2)) return;
if (!moving)
if (!altWhenClicked)
altWhenClicked = Input.GetKey(KeyCode.LeftAlt);
if (!altWhenClicked)
{
if (!selected)
Selections.instance.ClickSelect(this);
if (!moving)
BeginMoving();
return;
}
if (dragging) return;
var entities = Selections.instance.eventsSelected;
if (entities.Count == 0)
{
entities = new() { this };
}
CommandManager.Instance.AddCommand(new Commands.Duplicate(entities));
dragging = true;
}
public void OnDown()
{
if (Conductor.instance.NotStopped()) return;
if (moving) return;
if (Input.GetMouseButton(0) && Timeline.instance.timelineState.selected)
{
if (Input.GetKey(KeyCode.LeftShift))
{
Selections.instance.ShiftClickSelect(this);
}
else
{
if (selected && clickTimer < 0.315f)
{
foreach (var marker in TimelineBlockManager.Instance.EntityMarkers.Values)
{
if (marker == this) continue;
if (marker.mouseOver)
{
Selections.instance.ClickSelect(marker);
marker.clickTimer = 0;
break;
}
}
}
else if (!selected)
Selections.instance.ClickSelect(this);
}
}
else if (Input.GetMouseButton(1))
{
EventParameterManager.instance.StartParams(entity);
}
else if (Input.GetMouseButton(2))
{
string[] datamodels = entity.datamodel.Split('/');
Debug.Log("Selected entity's datamodel : " + entity.datamodel);
bool isSwitchGame = datamodels[1] == "switchGame";
var game = EventCaller.instance.minigames[datamodels[isSwitchGame ? 2 : 0]];
int block = isSwitchGame ? 0 : game.actions.FindIndex(c => c.actionName == datamodels[1]) + 1;
if (!isSwitchGame)
{
// hardcoded stuff
// needs to happen because hidden blocks technically change the event index
if (game.fxOnly) block--;
if (datamodels[0] == "gameManager") block --;
}
GridGameSelector.instance.SelectGame(datamodels[isSwitchGame ? 2 : 0], block);
}
clickTimer = 0;
}
#endregion
#region ResizeEvents
public void ResizeEnter()
{
if (Conductor.instance.NotStopped()) return;
if (BoxSelection.instance.ActivelySelecting || !resizable || moving) return;
inResizeRegion = true;
Cursor.SetCursor(Timeline.instance.resizeCursor, new Vector2(14, 14), CursorMode.Auto);
}
public void ResizeExit()
{
inResizeRegion = false;
if (!resizing)
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
}
public void OnLeftDown()
{
if (BoxSelection.instance.ActivelySelecting) return;
if (resizable && selected)
{
ResetResize();
resizingLeft = true;
resizingLeftBL = (float)entity.beat + entity.length;
lastResizeBeat = entity.beat;
lastResizeLength = entity.length;
}
}
public void OnLeftUp()
{
if (resizable && resizingLeft)
{
ResetResize();
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
var b = entity.beat;
var l = entity.length;
entity.beat = lastResizeBeat;
entity.length = lastResizeLength;
CommandManager.Instance.AddCommand(new Commands.Resize(entity.guid, b, l));
}
}
public void OnRightDown()
{
if (BoxSelection.instance.ActivelySelecting) return;
if (resizable && selected)
{
ResetResize();
resizingRight = true;
lastResizeBeat = entity.beat;
lastResizeLength = entity.length;
}
}
public void OnRightUp()
{
if (resizable && resizingRight)
{
ResetResize();
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
var b = entity.beat;
var l = entity.length;
entity.beat = lastResizeBeat;
entity.length = lastResizeLength;
CommandManager.Instance.AddCommand(new Commands.Resize(entity.guid, b, l));
}
}
private void ResetResize()
{
resizingLeft = false;
resizingRight = false;
}
#endregion
#region Extra
public void SetColor(int type)
{
var c = EditorTheme.theme.LayerGradientIndex(type);
transform.GetChild(0).GetComponent<Image>().color = c;
if (resizable)
{
c = new Color(0, 0, 0, 0.35f);
resizeGraphic.color = c;
}
}
public void SetWidthHeight()
{
rectTransform.sizeDelta = new Vector2(entity.length * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight());
Icon.rectTransform.sizeDelta = new Vector2(Timeline.instance.LayerHeight() - 8, Timeline.instance.LayerHeight() - 8);
eventLabel.rectTransform.offsetMin = new Vector2(Icon.rectTransform.anchoredPosition.x + Icon.rectTransform.sizeDelta.x + 4, eventLabel.rectTransform.offsetMin.y);
}
public int GetTrack()
{
return (int)Mathf.Round(this.transform.localPosition.y / Timeline.instance.LayerHeight()) * -1;
}
private void OnDestroy()
{
// better safety net than canada's healthcare system
// this is still hilarious
// GameManager.instance.Beatmap.Entities.Remove(GameManager.instance.Beatmap.Entities.Find(c => c.eventObj = this));
}
#endregion
public void OnSelect()
{
// selectedImage.gameObject.SetActive(true);
}
public void OnDeselect()
{
// selectedImage.gameObject.SetActive(false);
}
}
}