Skip to content

Commit 7f8b05a

Browse files
committed
➕ Add animation above players in the editor
Fixes #3510
1 parent 84c01cd commit 7f8b05a

2 files changed

Lines changed: 263 additions & 0 deletions

File tree

lua/wire/client/node_editor/wire_fpga_editor.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ function Editor:SetV(bool)
10011001
self:SetVisible(bool)
10021002
self:SetKeyboardInputEnabled(bool)
10031003
self:GetParent():SetWorldClicker(wire_fpga_editor_worldclicker:GetBool() and bool) -- Enable this on the background so we can update FPGA's without closing the editor
1004+
RunConsoleCommand("wire_fpga_event", bool and "editor_open" or "editor_close")
10041005
end
10051006

10061007
function Editor:GetChosenFile()

lua/wire/stools/fpga.lua

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if SERVER then
3434
util.AddNetworkString("FPGA_Upload")
3535
util.AddNetworkString("FPGA_Download")
3636
util.AddNetworkString("FPGA_OpenEditor")
37+
util.AddNetworkString("wire_fpga_editor_status")
3738

3839
-- Reset
3940
function TOOL:Reload(trace)
@@ -204,6 +205,30 @@ if SERVER then
204205
end
205206
end)
206207

208+
local wire_fpga_event = {}
209+
210+
concommand.Add("wire_fpga_event", function(ply, command, args)
211+
local handler = wire_fpga_event[args[1]]
212+
if not handler then return end
213+
return handler(ply, args)
214+
end)
215+
216+
-- actual editor open/close handlers
217+
218+
function wire_fpga_event.editor_open(ply, args)
219+
net.Start("wire_fpga_editor_status")
220+
net.WriteEntity(ply)
221+
net.WriteBit(true)
222+
net.Broadcast()
223+
end
224+
225+
function wire_fpga_event.editor_close(ply, args)
226+
net.Start("wire_fpga_editor_status")
227+
net.WriteEntity(ply)
228+
net.WriteBit(false)
229+
net.Broadcast()
230+
end
231+
207232
end
208233

209234

@@ -367,4 +392,241 @@ if CLIENT then
367392
end
368393

369394
end
395+
396+
local busy_players = WireLib.RegisterPlayerTable()
397+
net.Receive("wire_fpga_editor_status", function(len)
398+
local ply = net.ReadEntity()
399+
local status = net.ReadBit() ~= 0
400+
if not IsValid(ply) or ply == LocalPlayer() then return end
401+
402+
busy_players[ply] = status or nil
403+
end)
404+
405+
local min = math.min
406+
local surface_DrawPoly = surface.DrawPoly
407+
local surface_SetDrawColor = surface.SetDrawColor
408+
409+
local nodeColor = Color(100,100,100,255)
410+
local lineColor = Color(70, 160, 255, 255)
411+
412+
local size = 100
413+
local padding = 100
414+
415+
local node1x, node1y = -padding * 1.5, padding
416+
local node2x, node2y = padding * 1.5, -padding
417+
418+
local anim = {
419+
tStart = 0,
420+
tEnd = 0,
421+
dir = 1,
422+
phase = 1,
423+
speed = 1,
424+
holdTime = 2.5,
425+
holdTimer = 0
426+
}
427+
local reversed = false
428+
429+
local node1 = { offset = 0, vel = 0 }
430+
local node2 = { offset = 0, vel = 0 }
431+
432+
local springStrength = 35
433+
local damping = 4
434+
local impulsePower = 100
435+
436+
local function UpdateSpring(node, ft)
437+
local force = -(springStrength * node.offset + damping * node.vel)
438+
node.vel = node.vel + force * ft
439+
node.offset = node.offset + node.vel * ft
440+
end
441+
442+
local curveSegments = 20
443+
local baseCurve = {}
444+
local thickness = 10
445+
local half = thickness * 0.5
446+
447+
local function BuildBaseCurve(dir)
448+
449+
baseCurve = {}
450+
451+
local startX, startY, endX, endY
452+
local cx1, cy1, cx2, cy2
453+
454+
if dir == 1 then
455+
startX = node1x + size * 0.5
456+
startY = node1y
457+
endX = node2x - size * 0.5
458+
endY = node2y
459+
460+
cx1, cy1 = 0, startY
461+
cx2, cy2 = 0, endY
462+
463+
reversed = false
464+
else
465+
startX = node2x + size * 0.5
466+
startY = node2y
467+
endX = node1x - size * 0.5
468+
endY = node1y
469+
470+
cx1, cy1 = startX + size * 2, startY + size * 2
471+
cx2, cy2 = endX - size * 2, endY - size * 2
472+
473+
reversed = true
474+
end
475+
476+
local prevX, prevY
477+
478+
for i = 0, curveSegments do
479+
local t = i / curveSegments
480+
481+
local it = 1 - t
482+
local it2 = it * it
483+
local it3 = it2 * it
484+
local t2 = t * t
485+
local t3 = t2 * t
486+
487+
local x =
488+
it3 * startX +
489+
3 * it2 * t * cx1 +
490+
3 * it * t2 * cx2 +
491+
t3 * endX
492+
493+
local y =
494+
it3 * startY +
495+
3 * it2 * t * cy1 +
496+
3 * it * t2 * cy2 +
497+
t3 * endY
498+
499+
if prevX then
500+
baseCurve[#baseCurve + 1] = {
501+
x1 = prevX,
502+
y1 = prevY,
503+
x2 = x,
504+
y2 = y,
505+
t1 = (i-1)/curveSegments,
506+
t2 = i/curveSegments
507+
}
508+
end
509+
510+
prevX, prevY = x, y
511+
end
512+
end
513+
514+
BuildBaseCurve(anim.dir)
515+
516+
local function DrawCachedCurve(tStart, tEnd)
517+
518+
surface_SetDrawColor(lineColor)
519+
520+
local startIndex = math.floor(tStart * curveSegments)
521+
local endIndex = math.floor(tEnd * curveSegments)
522+
523+
for i = startIndex + 1, endIndex do
524+
local seg = baseCurve[i]
525+
if seg then
526+
527+
local t1 = seg.t1
528+
local t2 = seg.t2
529+
530+
if reversed then
531+
t1 = 1 - t1
532+
t2 = 1 - t2
533+
end
534+
535+
local offset1 = node1.offset * (1 - t1) + node2.offset * t1
536+
local offset2 = node1.offset * (1 - t2) + node2.offset * t2
537+
538+
local y1 = seg.y1 + offset1
539+
local y2 = seg.y2 + offset2
540+
541+
local dx = seg.x2 - seg.x1
542+
local dy = y2 - y1
543+
544+
local nx = dy
545+
local ny = -dx
546+
547+
local len = (nx * nx + ny * ny) ^ 0.5
548+
if len > 0 then
549+
nx = nx / len * half
550+
ny = ny / len * half
551+
end
552+
553+
surface_DrawPoly({
554+
{ x = seg.x1 - nx, y = y1 - ny },
555+
{ x = seg.x1 + nx, y = y1 + ny },
556+
{ x = seg.x2 + nx, y = y2 + ny },
557+
{ x = seg.x2 - nx, y = y2 - ny }
558+
})
559+
end
560+
end
561+
end
562+
563+
hook.Add("PostPlayerDraw","wire_fpga_editor_status",function(ply)
564+
565+
if not busy_players[ply] then return end
566+
567+
local pos = ply:GetPos() + ply:GetUp() * (ply:OBBMaxs().z + 10)
568+
569+
local angle = (pos - EyePos()):GetNormalized():Angle()
570+
angle = Angle(0, angle.y, 0)
571+
angle:RotateAroundAxis(angle:Up(), -90)
572+
angle:RotateAroundAxis(angle:Forward(), 90)
573+
574+
local ft = FrameTime()
575+
576+
UpdateSpring(node1, ft)
577+
UpdateSpring(node2, ft)
578+
579+
if anim.phase == 1 then
580+
anim.tEnd = min(1, anim.tEnd + anim.speed * ft)
581+
if anim.tEnd >= 1 then
582+
anim.phase = 2
583+
anim.holdTimer = 0
584+
585+
if anim.dir == 1 then
586+
node2.vel = node2.vel - impulsePower
587+
else
588+
node1.vel = node1.vel - impulsePower
589+
end
590+
end
591+
592+
elseif anim.phase == 2 then
593+
anim.holdTimer = anim.holdTimer + ft
594+
if anim.holdTimer >= anim.holdTime then
595+
anim.phase = 3
596+
end
597+
598+
elseif anim.phase == 3 then
599+
anim.tStart = min(1, anim.tStart + anim.speed * ft)
600+
if anim.tStart >= 1 then
601+
anim.tStart = 0
602+
anim.tEnd = 0
603+
anim.phase = 1
604+
anim.dir = -anim.dir
605+
606+
BuildBaseCurve(anim.dir)
607+
end
608+
end
609+
610+
cam.Start3D2D(pos, angle, 0.05)
611+
612+
draw.RoundedBox(12,
613+
node1x - size*0.5,
614+
node1y - size*0.5 + node1.offset,
615+
size, size,
616+
nodeColor
617+
)
618+
619+
draw.RoundedBox(12,
620+
node2x - size*0.5,
621+
node2y - size*0.5 + node2.offset,
622+
size, size,
623+
nodeColor
624+
)
625+
626+
DrawCachedCurve(anim.tStart, anim.tEnd)
627+
628+
cam.End3D2D()
629+
630+
end)
631+
370632
end

0 commit comments

Comments
 (0)