-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplugin.lua
288 lines (232 loc) · 8.76 KB
/
plugin.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
--Stars and Bunnies [Hard] is good for testing, no LNs
LAYER_INCREMENT = 1000000 --each layer represents 1 universe of 1000000 ms
SV_INCREMENT = .125 --the distance between SVs will be .125 ms
tpearly = false --false: teleport starts at time, true: teleport ends at time
hidelayers = false --setting for hiding notes of non-current universes
--debug = "hi"
function draw()
imgui.Begin("Parallel Universe")
resetQueue()
--imgui.Text(debug)
state.IsWindowHovered = imgui.IsWindowHovered()
if #state.SelectedHitObjects > 0 then
local sv = map.GetScrollVelocityAt(state.SelectedHitObjects[1].StartTime)
imgui.Text("SV: " .. (sv and sv.Multiplier or 1))
imgui.Text("Layer: " .. state.SelectedHitObjects[1].EditorLayer)
imgui.Text("Universe: " .. getUniverse(state.SelectedHitObjects[1].StartTime)) --"universe" of the note
end
if imgui.Button("Update Layer") then
hideLayer(state.CurrentLayer)
end
tooltip("Places/Updates SVs to move notes to their correct positions")
if imgui.Button("Update All") then
hideAll()
end
tooltip("Places/Updates SVs to move notes to their correct positions")
if imgui.Button("Restore Layer") then
unhideLayer(state.CurrentLayer)
end
tooltip("Removes/Updates SVs to restore notes to their original positions")
if imgui.Button("Restore All") then
unhideAll()
end
tooltip("Removes/Updates SVs to restore notes to their original positions")
if imgui.Button("Teleport Backward") then
local time = state.SelectedHitObjects[1].StartTime
if tpearly then time = time - SV_INCREMENT end
teleport(time, -1)
end
tooltip("Teleports backward one universe at time of selected note")
if imgui.Button("Teleport Forward") then
local time = state.SelectedHitObjects[1].StartTime
if tpearly then time = time - SV_INCREMENT end
teleport(time, 1)
end
tooltip("Teleports forward one universe at time of selected note")
if imgui.Button("Clean SVs") then
cleanSV()
end
tooltip("Removes redundant SVs")
--[[if imgui.Button("Increase SV") then
increaseSV(state.SongTime, 0.5)
end]]--
_, tpearly = imgui.Checkbox("Place Teleport Earlier", tpearly)
tooltip("Unchecked: Teleport starts at selected note\nChecked: Teleport ends at selected note")
_, hidelayers = imgui.Checkbox("Adjust Layer Visibility", hidelayers)
if imgui.IsItemDeactivated() then showAllLayers() end
tooltip("Only notes that can be seen by the player are visible in editor\nMay cause lag")
if hidelayers then adjustLayerVisibility() end
if utils.IsKeyPressed(87) then
local notes = state.SelectedHitObjects
actions.MoveHitObjectsToLayer(state.CurrentLayer, notes)
end
if utils.IsKeyPressed(69) then
local notes = state.SelectedHitObjects
teleport(state.SelectedHitObjects[1].StartTime, -1)
end
if utils.IsKeyPressed(82) then
local notes = state.SelectedHitObjects
teleport(state.SelectedHitObjects[1].StartTime, 1)
end
performQueue()
imgui.End()
end
function tooltip(text)
if imgui.IsItemHovered() then
imgui.BeginTooltip()
imgui.Text(text)
imgui.EndTooltip()
end
end
function queue(type, arg1, arg2, arg3, arg4)
arg1 = arg1 or nil
arg2 = arg2 or nil
arg3 = arg3 or nil
arg4 = arg4 or nil
local action = utils.CreateEditorAction(type, arg1, arg2, arg3, arg4)
table.insert(action_queue, action)
end
function resetQueue()
action_queue = {}
add_sv_queue = {}
end
function performQueue()
if #add_sv_queue > 0 then queue(action_type.AddScrollVelocityBatch, add_sv_queue) end
if #action_queue > 0 then actions.PerformBatch(action_queue) end
end
function setLayerHidden(layer, hidden)
if layer.Hidden != hidden then actions.ToggleLayerVisibility(layer) end
end
function showAllLayers()
for _, layer in pairs(map.EditorLayers) do
setLayerHidden(layer, false)
end
setLayerHidden(map.DefaultLayer, false)
end
function adjustLayerVisibility()
local universe = math.floor(getUniverse(state.SongTime))
for i, layer in pairs(map.EditorLayers) do
setLayerHidden(layer, i != universe)
end
setLayerHidden(map.DefaultLayer, universe != 0)
end
function hideLayer(layer)
local notes = getNotesInLayer(layer)
local index = getLayerIndex(layer)
for _, note in pairs(notes) do
local time = note.StartTime
--prevents adjusting the SVs of already hidden notes
local universe = math.floor(getUniverse(time))
local distance = (index - universe) * LAYER_INCREMENT * 100
local multiplier = distance / 100 / SV_INCREMENT
if distance != 0 then
--actions aren't performed until end of frame,
--so all three multipliers are based off of original SV
increaseSV(time - SV_INCREMENT, multiplier)
increaseSV(time, -1 * multiplier)
increaseSV(time + SV_INCREMENT, 0)
end
end
end
function hideAll()
for _, layer in pairs(map.EditorLayers) do
hideLayer(layer)
end
hideLayer(map.DefaultLayer)
end
function unhideLayer(layer)
local notes = getNotesInLayer(layer)
for _, note in pairs(notes) do
local time = note.StartTime
local noteuniverse = math.floor(getUniverse(time))
local universe = math.floor(getUniverse(time - 1))
--assuming all notes' original positions are in the first universe
local distance = -1 * (noteuniverse - universe) * LAYER_INCREMENT * 100
local multiplier = distance / 100 / SV_INCREMENT
if distance != 0 then
increaseSV(time - SV_INCREMENT, multiplier)
increaseSV(time, -1 * multiplier)
--increaseSV(time + SV_INCREMENT, 0)
end
end
end
function unhideAll()
for _, layer in pairs(map.EditorLayers) do
unhideLayer(layer)
end
unhideLayer(map.DefaultLayer)
end
function increaseSV(time, multiplier)
--assuming initial sv multiplier is 1
local sv
if map.ScrollVelocities[1] and time < map.ScrollVelocities[1].StartTime then sv = utils.CreateScrollVelocity(-1e309, 1)
else sv = map.GetScrollVelocityAt(time) or utils.CreateScrollVelocity(-1e309, 1) end
if sv.StartTime == time then
queue(action_type.ChangeScrollVelocityMultiplierBatch, {sv}, sv.Multiplier + multiplier)
else
local newsv = utils.CreateScrollVelocity(time, sv.Multiplier + multiplier)
table.insert(add_sv_queue, newsv)
end
end
function cleanSV()
local svs = map.ScrollVelocities
local redundants = {}
local prevmult = 1
for _, sv in pairs(svs) do
if sv.Multiplier == prevmult then
table.insert(redundants, sv)
end
prevmult = sv.Multiplier
end
queue(action_type.RemoveScrollVelocityBatch, redundants)
end
function teleport(time, diff)
increaseSV(time, diff * LAYER_INCREMENT / SV_INCREMENT)
increaseSV(time + SV_INCREMENT, 0)
end
function getPositionFromTime(time)
--[[
if using this function multiple times in one frame,
it may be faster to set ScrollVelocities = map.ScrollVelocities in draw()
and then set local svs = ScrollVelocities inside this function
]]
local svs = map.ScrollVelocities
if #svs == 0 or time < svs[1].StartTime then
return math.floor(time * 100)
end
local position = math.floor(svs[1].StartTime * 100)
local i = 2
while i <= #svs do
if time < svs[i].StartTime then
break
else
position = position + math.floor((svs[i].StartTime - svs[i - 1].StartTime) * svs[i - 1].Multiplier * 100)
end
i = i + 1
end
i = i - 1
position = position + math.floor((time - svs[i].StartTime) * svs[i].Multiplier * 100)
return position
end
function getUniverse(time)
return getPositionFromTime(time) / (LAYER_INCREMENT * 100)
end
function getLayerIndex(layer)
if layer == map.DefaultLayer then return 0 end
for i, l in pairs(map.EditorLayers) do
if l == layer then return i end
end
end
function getNotesInLayer(layer)
local notes = map.HitObjects
local layernotes = {}
local layerindex = getLayerIndex(layer)
local lasttime = false
for _, note in pairs(notes) do
if note.EditorLayer == layerindex and note.StartTime != lasttime then
table.insert(layernotes, note)
lasttime = note.StartTime
end
end
return layernotes
end