mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
1251 lines
34 KiB
Python
Executable file
1251 lines
34 KiB
Python
Executable file
# Copyright 2025 - Solely by BrotherBoard
|
|
# Intended for personal use only
|
|
# Bug? Feedback? Telegram >> @BroBordd
|
|
|
|
"""
|
|
Replay v2.5 - Simple replay player
|
|
|
|
Experimental. Feedback is appreciated.
|
|
Adds a button to pause menu and watch menu.
|
|
|
|
Features:
|
|
- Common features (pause/play/seek/speed/replay)
|
|
- Press on progress bar to seek anywhere
|
|
- Advanced free camera target control
|
|
- Ability to zoom in/out to target
|
|
- Uses pybrp to display how long a replay is
|
|
- Good UI with detailed toast pop ups
|
|
- Ability to show/hide UI
|
|
- Uses threading everywhere
|
|
"""
|
|
|
|
from babase import Plugin
|
|
from bauiv1 import (
|
|
get_virtual_screen_size as res,
|
|
get_special_widget as gsw,
|
|
clipboard_set_text as COPY,
|
|
get_replays_dir as rdir,
|
|
containerwidget as ocw,
|
|
screenmessage as push,
|
|
spinnerwidget as spin,
|
|
buttonwidget as obw,
|
|
fade_screen as fade,
|
|
scrollwidget as sw,
|
|
SpecialChar as sc,
|
|
imagewidget as iw,
|
|
textwidget as otw,
|
|
gettexture as gt,
|
|
apptimer as teck,
|
|
AppTimer as tock,
|
|
getsound as gs,
|
|
UIScale as UIS,
|
|
charstr as cs,
|
|
Call,
|
|
app
|
|
)
|
|
from bascenev1 import (
|
|
set_replay_speed_exponent as SET,
|
|
get_replay_speed_exponent as GET,
|
|
new_replay_session as PLAY,
|
|
resume_replay as RESUME,
|
|
pause_replay as PAUSE,
|
|
seek_replay as SEEK,
|
|
is_in_replay as ON
|
|
)
|
|
from _babase import (
|
|
set_camera_position as SCP,
|
|
get_camera_position as GCP,
|
|
set_camera_manual as SCM,
|
|
set_camera_target as SCT,
|
|
get_camera_target as GCT
|
|
)
|
|
from os.path import join, dirname, getsize, basename
|
|
from time import time, strftime, gmtime
|
|
from random import uniform as uf
|
|
from threading import Thread
|
|
from os import listdir as ls
|
|
from struct import unpack
|
|
|
|
class Replay:
|
|
VER = '2.5'
|
|
COL1 = (0.18,0.18,0.18)
|
|
COL2 = (1,1,1)
|
|
COL3 = (0,1,0)
|
|
COL4 = (0,1,1)
|
|
BUSY = False
|
|
@classmethod
|
|
def BUS(c,b=None):
|
|
if b is None: return c.BUSY
|
|
c.BUSY = b
|
|
def __init__(s,source=None):
|
|
s.sl = s.rn = s.buf = None
|
|
s.ohno = False
|
|
s._h = _H()
|
|
s.p = s.cw(
|
|
src=source.get_screen_space_center(),
|
|
p=GOS(),
|
|
size=(400,500),
|
|
oac=lambda:(ocw(s.p,transition='out_scale' if source and source.exists() else 'out_left'),s.snd('laser'),s.trs.stop())
|
|
)
|
|
s.trs = s.snd('powerup01')
|
|
s.tw(
|
|
p=s.p,
|
|
h_align='center',
|
|
text='Replay',
|
|
pos=(175,460),
|
|
scale=2
|
|
)
|
|
sy = 360
|
|
p1 = sw(
|
|
parent=s.p,
|
|
size=(sy,sy),
|
|
position=(25,80)
|
|
)
|
|
s.rd = rdir()
|
|
a = [_ for _ in ls(s.rd) if _.endswith('.brp')]
|
|
v = 30*len(a)
|
|
p2 = ocw(
|
|
parent=p1,
|
|
background=False,
|
|
size=(sy,v)
|
|
)
|
|
s.kids = []
|
|
for i,_ in enumerate(a):
|
|
t = s.tw(
|
|
p=p2,
|
|
click_activate=True,
|
|
selectable=True,
|
|
pos=(0,v-30*i-30),
|
|
text=_,
|
|
maxwidth=sy,
|
|
size=(sy,30),
|
|
color=s.COL2,
|
|
oac=Call(s.hl,i,_)
|
|
)
|
|
s.kids.append(t)
|
|
s.psrc = None
|
|
for _ in range(3):
|
|
b = s.bw(
|
|
p=s.p,
|
|
pos=(25+120*_,30),
|
|
size=(120,40),
|
|
label=['Show','Copy','Run'][_],
|
|
oac=Call(s.con,[s.show,s.copy,s.play][_]),
|
|
icon=gt(['folder','file','nextLevelIcon'][_])
|
|
)
|
|
if _ == 2: s.psrc = b
|
|
def snd(s,t):
|
|
h = gs(t)
|
|
h.play()
|
|
teck(uf(0.14,0.17),h.stop)
|
|
return h
|
|
def get(s):
|
|
return join(s.rd,s.rn)
|
|
def copy(s):
|
|
s.snd('dingSmallHigh')
|
|
COPY(s.get())
|
|
push('Copied replay path to clipboard!',color=s.COL3)
|
|
def show(s):
|
|
gs('ding').play()
|
|
push(s.get(),color=s.COL3)
|
|
def con(s,f):
|
|
if s.sl is None: BTW('Select a replay!'); return
|
|
if ON(): BTW('A replay is already running!'); return
|
|
return f()
|
|
def hl(s,i,n):
|
|
if s.sl == i:
|
|
s.psrc = s.kids[i]
|
|
s.play()
|
|
return
|
|
s.sl = i
|
|
s.rn = n
|
|
[otw(_,color=s.COL2) for _ in s.kids]
|
|
otw(s.kids[i],color=s.COL3)
|
|
def play(s):
|
|
if s.BUS(): return
|
|
s.BUS(True)
|
|
gs('deek').play()
|
|
s.load()
|
|
def load(s):
|
|
src = s.psrc.get_screen_space_center()
|
|
if s.psrc.get_widget_type() == 'text':
|
|
src = (src[0]-170,src[1])
|
|
s.parc = c = s.cw(
|
|
src=src,
|
|
size=(300,200),
|
|
p=GOS()
|
|
)
|
|
s.tw(
|
|
p=c,
|
|
text='Player',
|
|
pos=(125,150),
|
|
h_align='center',
|
|
scale=1.4
|
|
)
|
|
spin(
|
|
parent=c,
|
|
size=60,
|
|
position=(75,100)
|
|
)
|
|
s.st = s.tw(
|
|
p=c,
|
|
text='Reading...',
|
|
pos=(115,87)
|
|
)
|
|
s.tpar = s.tw(
|
|
p=c,
|
|
pos=(125,30),
|
|
maxwidth=240,
|
|
text=f'{s.rn} with total of {getsize(s.get())} bytes\nstreaming bytes to pybrp_stream',
|
|
h_align='center'
|
|
)
|
|
s.tpar2 = s.tw(
|
|
p=c,
|
|
maxwidth=240,
|
|
pos=(30,20),
|
|
v_align='bottom'
|
|
)
|
|
s.par = [0,1]
|
|
teck(0.5,Thread(target=s.calc).start)
|
|
teck(0.5,s.fpar)
|
|
s.spy(s.calc2)
|
|
def fpar(s):
|
|
a,b = s.par
|
|
teck(0.1,s.fpar) if (a!=b) and (not s.ohno) else 0
|
|
if not a: return
|
|
p = a/b*100
|
|
t = '\u2588'*int(p)+'\u2591'*int(100-p)
|
|
if not s.ohno:
|
|
try:
|
|
otw(s.tpar,text=t)
|
|
otw(s.tpar2,text=f'{a} of {b} bytes read')
|
|
except: return
|
|
def calc(s):
|
|
try: s.buf = GMS(s._h,s.get(),s.par)
|
|
except: s.buf = 0
|
|
def calc2(s,t):
|
|
otw(s.st,text='Starting...' if t else 'Wait what?')
|
|
otw(s.tpar2,text=f'result was {t} milleseconds') if t else t
|
|
if not t:
|
|
s.ohno = True
|
|
otw(s.tpar,text='pybrp returned zero duration, error?\nclosing this window in 5 seconds')
|
|
otw(s.tpar2,text='')
|
|
teck(1 if t else 5,Call(s._play,t))
|
|
def spy(s,f,i=60):
|
|
if not i:
|
|
s.buf = None
|
|
f(None)
|
|
return
|
|
if s.buf is not None:
|
|
b = s.buf
|
|
s.buf = None
|
|
f(b)
|
|
return
|
|
teck(0.5,Call(s.spy,f,i-1))
|
|
def _play(s,t):
|
|
if t == 0:
|
|
BTW("Couldn't load replay!")
|
|
ocw(s.parc,transition='out_scale')
|
|
s.BUS(False)
|
|
return
|
|
SET(0)
|
|
fade(1)
|
|
Player(path=s.get(),duration=t)
|
|
s.BUS(False)
|
|
bw = lambda s,p=None,oac=None,pos=None,**k: obw(
|
|
parent=p,
|
|
color=s.COL1,
|
|
textcolor=s.COL2,
|
|
on_activate_call=oac,
|
|
position=pos,
|
|
button_type='square',
|
|
enable_sound=False,
|
|
**k
|
|
)
|
|
cw = lambda s,p=None,pos=None,src=None,oac=None,**k: ocw(
|
|
color=s.COL1,
|
|
parent=p,
|
|
position=pos,
|
|
scale_origin_stack_offset=src,
|
|
transition='in_scale',
|
|
on_outside_click_call=oac,
|
|
**k
|
|
)
|
|
tw = lambda s,color=None,oac=None,p=None,pos=None,**k: otw(
|
|
parent=p,
|
|
position=pos,
|
|
color=color or s.COL2,
|
|
on_activate_call=oac,
|
|
**k
|
|
)
|
|
|
|
class Player:
|
|
TICK = 0.01
|
|
COL0 = (0.5,0,0)
|
|
COL1 = (1,0,0)
|
|
COL2 = (0.5,0.5,0)
|
|
COL3 = (1,1,0)
|
|
COL4 = (0,0.5,0)
|
|
COL5 = (0,1,0)
|
|
COL6 = (0,0.5,0.5)
|
|
COL7 = (0,1,1)
|
|
COL8 = (0.6,0.6,0.6)
|
|
COL9 = (8,0,0)
|
|
COL10 = (0.5,0.25,0)
|
|
COL11 = (1,0.5,0)
|
|
COL12 = (0.5,0.25,0.5)
|
|
COL13 = (1,0.5,1)
|
|
COL14 = (0.5,0.5,0.5)
|
|
COL15 = (1,1,1)
|
|
COL16 = (0.1, 0.2, 0.4)
|
|
COL17 = (1, 1.7, 2)
|
|
def __init__(s,path,duration):
|
|
s.path = path
|
|
s.du = duration
|
|
s.ds = s.du / 1000
|
|
s.ps = s.nah = s.camon = s.snma = s.gay = False
|
|
s.caml = None
|
|
s.rn = s.st = s.pr = 0
|
|
s.camz = 1
|
|
[setattr(s,_,[]) for _ in ['kids','camkids','hdkids','snkids','snuikids']]
|
|
PLAY(path)
|
|
x,y = res()
|
|
s.sy = 80
|
|
s.p = ocw(
|
|
size=(x,s.sy),
|
|
stack_offset=(0,-y/2+s.sy/2),
|
|
background=False
|
|
)
|
|
s.bg = iw(
|
|
parent=s.p,
|
|
texture=gt('black'),
|
|
size=(x+3,s.sy+5),
|
|
position=(0,-2),
|
|
opacity=0.4
|
|
)
|
|
s.mkui()
|
|
s.mkhd()
|
|
# finally
|
|
s.sp = 1
|
|
s.foc()
|
|
s.play()
|
|
def mkhd(s):
|
|
f = s.hdkids.append
|
|
s.tex=['\u25bc','\u25b2']
|
|
s.kekb = s.bw(
|
|
p=s.p,
|
|
pos=(20,15),
|
|
size=(50,50),
|
|
oac=s.kek,
|
|
color=s.COL10
|
|
)
|
|
f(s.kekb)
|
|
s.kekt = otw(
|
|
parent=s.p,
|
|
text=s.tex[s.nah],
|
|
position=(44,30),
|
|
scale=2,
|
|
shadow=0.4,
|
|
color=s.COL11
|
|
)
|
|
f(s.kekt)
|
|
f(iw(
|
|
parent=s.p,
|
|
position=(18,13),
|
|
size=(54,54),
|
|
color=s.COL10,
|
|
texture=gt('white'),
|
|
opacity=0.4
|
|
))
|
|
def killhd(s):
|
|
[_.delete() for _ in s.hdkids]
|
|
s.hdkids.clear()
|
|
def mkui(s):
|
|
s.up = True
|
|
f = s.kids.append
|
|
x,y = res()
|
|
sy = s.sy
|
|
p = s.p
|
|
# exit
|
|
f(s.bw(
|
|
p=p,
|
|
pos=(x-65,15),
|
|
size=(50,50),
|
|
color=s.COL0,
|
|
oac=s.bye
|
|
))
|
|
c = s.COL1
|
|
f(iw(
|
|
parent=p,
|
|
texture=gt('crossOut'),
|
|
color=(c[0]*10,c[1]*10,c[2]*10),
|
|
position=(x-60,20),
|
|
size=(40,40)
|
|
))
|
|
# speed
|
|
for _ in range(2):
|
|
a = [
|
|
'FAST_FORWARD_BUTTON',
|
|
'REWIND_BUTTON'
|
|
][_]
|
|
pos = (x-130-260*_,15)
|
|
f(s.bw(
|
|
p=p,
|
|
pos=pos,
|
|
size=(50,50),
|
|
color=s.COL2,
|
|
oac=Call(s.boost,[1,-1][_]),
|
|
repeat=True
|
|
))
|
|
f(otw(
|
|
parent=p,
|
|
text=cs(getattr(sc,a)),
|
|
color=s.COL3,
|
|
position=(pos[0]-2,pos[1]+13),
|
|
h_align='center',
|
|
v_align='center',
|
|
scale=1.8,
|
|
shadow=0.3
|
|
))
|
|
# seek
|
|
for _ in range(2):
|
|
a = [
|
|
'RIGHT_ARROW',
|
|
'LEFT_ARROW'
|
|
][_]
|
|
pos = (x-195-130*_,15)
|
|
f(s.bw(
|
|
p=p,
|
|
pos=pos,
|
|
size=(50,50),
|
|
color=s.COL4,
|
|
oac=Call(s.seek,[1,-1][_]),
|
|
repeat=True
|
|
))
|
|
f(otw(
|
|
parent=p,
|
|
text=cs(getattr(sc,a)),
|
|
color=s.COL5,
|
|
position=(pos[0]-1,pos[1]+12),
|
|
h_align='center',
|
|
v_align='center',
|
|
scale=1.7,
|
|
shadow=0.2
|
|
))
|
|
# pause
|
|
pos = (x-260,15)
|
|
f(s.bw(
|
|
p=p,
|
|
pos=pos,
|
|
size=(50,50),
|
|
color=s.COL6,
|
|
oac=s.toggle
|
|
))
|
|
s.tt = otw(
|
|
parent=p,
|
|
color=s.COL7,
|
|
position=(pos[0]+12,pos[1]+11),
|
|
scale=1.5,
|
|
shadow=0.3
|
|
)
|
|
f(s.tt)
|
|
s.toggle(dry=True)
|
|
# replay
|
|
pos = (x-455,15)
|
|
f(s.bw(
|
|
p=p,
|
|
pos=pos,
|
|
size=(50,50),
|
|
color=s.COL12,
|
|
oac=s.rloop
|
|
))
|
|
c = s.COL13
|
|
sk = 1.5
|
|
f(iw(
|
|
parent=p,
|
|
texture=gt('replayIcon'),
|
|
color=(c[0]*sk,c[1]*sk,c[2]*sk),
|
|
position=(pos[0]+2,pos[1]+1),
|
|
size=(47,47),
|
|
))
|
|
# progress
|
|
pos = (285,sy/2-2)
|
|
s.px = x-790
|
|
f(iw(
|
|
parent=p,
|
|
texture=gt('white'),
|
|
size=(s.px,5),
|
|
position=pos,
|
|
opacity=0.4,
|
|
color=s.COL8
|
|
))
|
|
s.nbp = (pos[0]-24,pos[1]-22)
|
|
s.nb = iw(
|
|
parent=p,
|
|
texture=gt('nub'),
|
|
size=(50,50),
|
|
position=s.nbp,
|
|
opacity=0.4,
|
|
color=s.COL9
|
|
)
|
|
f(s.nb)
|
|
# timestamp
|
|
s.ct = otw(
|
|
parent=p,
|
|
position=(155,40),
|
|
color=s.COL7,
|
|
text=FOR(s.rn-s.st)
|
|
)
|
|
f(s.ct)
|
|
f(otw(
|
|
parent=p,
|
|
position=(155,11),
|
|
text=FOR(s.ds),
|
|
color=s.COL6
|
|
))
|
|
# sensor
|
|
sx,sy = (285,15)
|
|
n = 100
|
|
tp = s.px/n
|
|
for _ in range(n):
|
|
f(obw(
|
|
label='',
|
|
parent=p,
|
|
position=(sx+tp*_,sy),
|
|
size=(tp,50),
|
|
texture=gt('empty'),
|
|
enable_sound=False,
|
|
on_activate_call=Call(s.jump,_/n),
|
|
selectable=False
|
|
))
|
|
# camera
|
|
f(s.bw(
|
|
p=s.p,
|
|
pos=(85,15),
|
|
size=(50,50),
|
|
color=s.COL14,
|
|
oac=s.cam
|
|
))
|
|
c = s.COL15
|
|
sk = 1.5
|
|
f(iw(
|
|
parent=s.p,
|
|
texture=gt('achievementOutline'),
|
|
position=(88,18),
|
|
color=(c[0]*sk,c[1]*sk,c[2]*sk),
|
|
size=(45,45)
|
|
))
|
|
# info
|
|
ix,iy = (443,98)
|
|
s.ok = iw(
|
|
texture=gt('white'),
|
|
position=(x-456,100),
|
|
parent=p,
|
|
size=(ix,iy),
|
|
opacity=0
|
|
)
|
|
f(s.ok)
|
|
s.ok2 = otw(
|
|
position=(x-ix+182.5,iy+64),
|
|
h_align='center',
|
|
scale=1.2,
|
|
parent=p,
|
|
maxwidth=ix-20
|
|
)
|
|
f(s.ok2)
|
|
s.ok3 = otw(
|
|
position=(x-ix+182.5,iy+10),
|
|
h_align='center',
|
|
parent=p,
|
|
maxwidth=ix-20
|
|
)
|
|
f(s.ok3)
|
|
def mkcamui(s):
|
|
f = s.camkids.append
|
|
x,y = (19,100)
|
|
s.cambg = iw(
|
|
parent=s.p,
|
|
size=(235,260),
|
|
position=(x,y),
|
|
texture=gt('white'),
|
|
color=s.COL14,
|
|
opacity=0.05
|
|
)
|
|
f(s.cambg)
|
|
# tip
|
|
s.cambg2 = iw(
|
|
parent=s.p,
|
|
size=(235,100),
|
|
opacity=0.05,
|
|
position=(x,y+267),
|
|
color=s.COL14,
|
|
texture=gt('white')
|
|
)
|
|
f(s.cambg2)
|
|
s.fcam()
|
|
f(otw(
|
|
parent=s.p,
|
|
h_align='center',
|
|
v_align='center',
|
|
text='To maintain animated\nsmooth camera, keep\nzoom at auto.',
|
|
maxwidth=205,
|
|
max_height=190,
|
|
position=(x+92,y+300),
|
|
color=s.COL15
|
|
))
|
|
# reset
|
|
f(s.bw(
|
|
p=s.p,
|
|
label='Reset',
|
|
color=s.COL14,
|
|
textcolor=s.COL15,
|
|
size=(205,30),
|
|
pos=(x+15,y+7),
|
|
oac=s.camr
|
|
))
|
|
# seperator
|
|
f(iw(
|
|
parent=s.p,
|
|
size=(219,2),
|
|
position=(x+8,y+44),
|
|
texture=gt('white'),
|
|
color=s.COL15,
|
|
opacity=0.6
|
|
))
|
|
# look
|
|
f(s.bw(
|
|
p=s.p,
|
|
label='Look',
|
|
pos=(x+15,y+53),
|
|
color=s.COL14,
|
|
textcolor=s.COL15,
|
|
size=(205,30),
|
|
oac=s.look
|
|
))
|
|
s.ltw = otw(
|
|
parent=s.p,
|
|
text=str(RND(s.caml) if s.caml else 'players'),
|
|
v_align='center',
|
|
h_align='center',
|
|
position=(x+92,y+90),
|
|
color=s.COL14,
|
|
maxwidth=205,
|
|
max_height=40
|
|
)
|
|
f(s.ltw)
|
|
f(otw(
|
|
parent=s.p,
|
|
text='Currently looking at:',
|
|
v_align='center',
|
|
h_align='center',
|
|
position=(x+92,y+120),
|
|
color=s.COL15,
|
|
maxwidth=205,
|
|
max_height=40
|
|
))
|
|
# seperator
|
|
f(iw(
|
|
parent=s.p,
|
|
size=(219,2),
|
|
position=(x+8,y+154),
|
|
texture=gt('white'),
|
|
color=s.COL15,
|
|
opacity=0.6
|
|
))
|
|
# zoom
|
|
[f(s.bw(
|
|
p=s.p,
|
|
label=['-','+'][_],
|
|
pos=(x+13+113*_,y+163),
|
|
color=s.COL14,
|
|
textcolor=s.COL15,
|
|
size=(98,30),
|
|
repeat=True,
|
|
oac=Call(s.zoom,[1,-1][_])
|
|
)) for _ in [0,1]]
|
|
s.ztw = otw(
|
|
parent=s.p,
|
|
text=f'x{round(0.5**(s.camz-1),2)}' if s.camz != 1 else 'x1.0' if s.gay else 'auto',
|
|
v_align='center',
|
|
h_align='center',
|
|
position=(x+92,y+200),
|
|
color=s.COL14,
|
|
maxwidth=205,
|
|
max_height=40
|
|
)
|
|
f(s.ztw)
|
|
f(otw(
|
|
parent=s.p,
|
|
text='Current zoom:',
|
|
v_align='center',
|
|
h_align='center',
|
|
position=(x+92,y+227),
|
|
color=s.COL15,
|
|
maxwidth=205,
|
|
max_height=40
|
|
))
|
|
def zoom(s,i):
|
|
n = round(s.camz+i*0.05,2)
|
|
if s.camz == 1 and not s.gay:
|
|
SCM(True)
|
|
s.camp = GCP()
|
|
s.caml = GCT()
|
|
otw(s.ltw,text=str(RND(s.caml)))
|
|
if n == 1 and not s.gay:
|
|
SCM(False)
|
|
s.caml = None
|
|
otw(s.ltw,text='players')
|
|
s.camz = n
|
|
otw(s.ztw,text=f'x{round(0.5**(n-1),2)}' if n != 1 else 'x1.0' if s.gay else 'auto')
|
|
s.zom()
|
|
def look(s):
|
|
s.killui()
|
|
s.killhd()
|
|
s.fkek(0.4,-0.1)
|
|
s.camlo = s.caml
|
|
s.campo = GCP()
|
|
s.gayo = s.gay
|
|
s.mksns()
|
|
s.mksnui()
|
|
s.mksnb()
|
|
s.mksni()
|
|
def _look(s,x,y):
|
|
o = s.caml or GCT()
|
|
sk = 0.7*s.camz
|
|
s.caml = n = (o[0]+x*sk,o[1]+y*sk,o[2])
|
|
0 if s.snma else otw(s.snt,text=str(RND(n)))
|
|
s.camp = GCP()
|
|
if s.camz != 1: s.gay = True
|
|
s.camz = 1
|
|
def foc(s):
|
|
s.tfoc = tock(0.01,s.focus,repeat=True)
|
|
def focus(s):
|
|
SCT(*s.caml) if s.caml else 0
|
|
def zom(s):
|
|
if s.camz == 1 and not s.gay: return
|
|
z = s.camz
|
|
tx,ty,tz = GCT()
|
|
px,py,pz = s.camp
|
|
npx = tx+(px-tx)*z
|
|
npy = ty+(py-ty)*z
|
|
npz = tz+(pz-tz)*z
|
|
SCP(npx,npy,npz)
|
|
def fockill(s):
|
|
s.tfoc = None
|
|
def snsave(s):
|
|
s.snbye()
|
|
def snbye(s):
|
|
s.killsn()
|
|
s.mkui()
|
|
s.mkhd()
|
|
s.fkek(0,0.1)
|
|
s.pro()
|
|
def mksns(s):
|
|
x,y = res()
|
|
sz = 50
|
|
a = int(x/sz)
|
|
b = int(y/sz)
|
|
ha = a/2
|
|
hb = b/2
|
|
[s.snkids.append(obw(
|
|
parent=s.p,
|
|
size=(sz,sz),
|
|
position=(i*sz,j*sz),
|
|
texture=gt('empty'),
|
|
enable_sound=False,
|
|
on_activate_call=Call(s._look,i-ha,j-hb),
|
|
label='',
|
|
repeat=True
|
|
))
|
|
for i in range(a)
|
|
for j in range(b)]
|
|
def mksnui(s):
|
|
f = s.snuikids.append
|
|
f(iw(
|
|
parent=s.p,
|
|
position=(0,3),
|
|
color=s.COL14,
|
|
opacity=0.4,
|
|
texture=gt('white'),
|
|
size=(232,190)
|
|
))
|
|
# buttons
|
|
f(s.bw(
|
|
p=s.p,
|
|
pos=(14,50),
|
|
size=(204,30),
|
|
label='Target Players',
|
|
color=s.COL14,
|
|
textcolor=s.COL15,
|
|
oac=s.sntar
|
|
))
|
|
f(s.bw(
|
|
p=s.p,
|
|
pos=(10,90),
|
|
color=s.COL14,
|
|
label='Cancel',
|
|
size=(99,30),
|
|
textcolor=s.COL15,
|
|
oac=s.sncancel
|
|
))
|
|
f(s.bw(
|
|
p=s.p,
|
|
pos=(123,90),
|
|
color=s.COL14,
|
|
label='Save',
|
|
size=(99,30),
|
|
textcolor=s.COL15,
|
|
oac=s.snsave
|
|
))
|
|
# info
|
|
f(otw(
|
|
parent=s.p,
|
|
position=(90,160),
|
|
color=s.COL15,
|
|
text='Currently looking at:',
|
|
h_align='center',
|
|
maxwidth=220
|
|
))
|
|
s.snt = otw(
|
|
parent=s.p,
|
|
position=(90,130),
|
|
color=s.COL14,
|
|
h_align='center',
|
|
text=str(RND(s.caml) if s.caml else 'players')
|
|
)
|
|
f(s.snt)
|
|
# tip
|
|
f(iw(
|
|
parent=s.p,
|
|
position=(0,200),
|
|
color=s.COL14,
|
|
opacity=0.4,
|
|
texture=gt('white'),
|
|
size=(232,110)
|
|
))
|
|
f(otw(
|
|
parent=s.p,
|
|
position=(90,240),
|
|
text='Longpress anywhere\nto look around. Tap on \nsomething to look at it.\nPause for calmer control!',
|
|
h_align='center',
|
|
v_align='center',
|
|
maxwidth=225,
|
|
max_height=105
|
|
))
|
|
# crosshair
|
|
x,y = res()
|
|
h = 20
|
|
[f(iw(
|
|
parent=s.p,
|
|
position=(x/2,y/2-h/2+h*0.1) if _ else (x/2-h/2,y/2+h*0.1),
|
|
size=(3,h*1.15) if _ else (h*1.15,3),
|
|
color=s.COL1,
|
|
texture=gt('white')
|
|
)) for _ in [0,1]]
|
|
# top
|
|
k = 60
|
|
for j in range(2):
|
|
f(iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
position=(x/2+[-k,k-h][j],y/2+k),
|
|
size=(h*1.1,3)
|
|
))
|
|
# right
|
|
for j in range(2):
|
|
f(iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
position=(x/2+k,y/2+[k-h,-k+h*0.3][j]),
|
|
size=(3,h*+1.1)
|
|
))
|
|
# bottom
|
|
for j in range(2):
|
|
f(iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
position=(x/2+[-k,k-h][j],y/2-h/2-k+h*0.8),
|
|
size=(h*1.1,3)
|
|
))
|
|
# left
|
|
for j in range(2):
|
|
f(iw(
|
|
parent=s.p,
|
|
texture=gt('white'),
|
|
color=s.COL1,
|
|
position=(x/2-k,y/2+[k-h,-k+h*0.3][j]),
|
|
size=(3,h*1.1)
|
|
))
|
|
def killsnui(s):
|
|
[_.delete() for _ in s.snuikids]
|
|
def snhide(s):
|
|
if getattr(s,'snbusy',0): return
|
|
s.snma = not s.snma
|
|
s.snbusy = True
|
|
if s.snma:
|
|
s.snanim(204,14,-1)
|
|
obw(s.snbtn,label=cs(sc.UP_ARROW))
|
|
s.killsnui()
|
|
else:
|
|
obw(s.snbtn,texture=gt('white'))
|
|
s.snanim(36,7,1)
|
|
iw(s.sni,opacity=0)
|
|
def mksni(s):
|
|
s.sni = iw(
|
|
parent=s.p,
|
|
position=(7,8),
|
|
color=s.COL14,
|
|
opacity=0,
|
|
size=(36,33),
|
|
texture=gt('white')
|
|
)
|
|
s.snkids.append(s.sni)
|
|
def mksnb(s):
|
|
s.snbtn = s.bw(
|
|
p=s.p,
|
|
pos=(14,10),
|
|
color=s.COL14,
|
|
label='Cinema Mode',
|
|
size=(204,30),
|
|
textcolor=s.COL15,
|
|
oac=s.snhide
|
|
)
|
|
s.snkids.append(s.snbtn)
|
|
def snanim(s,a,b,i):
|
|
a += (163/35)*i
|
|
b += 0.2*i
|
|
obw(s.snbtn,size=(a,30),position=(b,10))
|
|
if not (14>=b>=7):
|
|
s.snbusy = False
|
|
if s.snma:
|
|
obw(s.snbtn,texture=gt('empty'))
|
|
iw(s.sni,opacity=0.4)
|
|
else:
|
|
s.mksnui()
|
|
s.snbtn.delete()
|
|
s.mksnb()
|
|
obw(s.snbtn,label='Cinema Mode')
|
|
return
|
|
teck(0.004,Call(s.snanim,a,b,i))
|
|
def killsn(s):
|
|
s.killsnui()
|
|
[_.delete() for _ in s.snkids]
|
|
def all(s):
|
|
return s.trash()+s.hdkids+s.snkids
|
|
def sntar(s):
|
|
s.caml = None
|
|
otw(s.snt,text='players')
|
|
if s.camz != 1 or s.gay:
|
|
s.camz = 1
|
|
s.gay = False
|
|
SCM(False)
|
|
def sncancel(s):
|
|
s.caml = s.camlo
|
|
s.camp = s.campo
|
|
s.gay = s.gayo
|
|
if s.camz != 1 or s.gay:
|
|
SCM(True)
|
|
SCP(*s.camp)
|
|
s.snbye()
|
|
def cam(s):
|
|
if s.camon:
|
|
s.camon = False
|
|
[_.delete() for _ in s.camkids]
|
|
s.camkids.clear()
|
|
s.fcam(0.4,-0.1)
|
|
else:
|
|
s.camon = True
|
|
s.mkcamui()
|
|
def camr(s):
|
|
SCM(False)
|
|
s.caml = None
|
|
s.gay = False
|
|
s.camz = 1
|
|
otw(s.ltw,text='players')
|
|
otw(s.ztw,text='auto')
|
|
def fcam(s,i=0,a=0.1):
|
|
if i > 0.4 or i < 0:
|
|
if a < 0: s.cambg.delete()
|
|
return
|
|
if not s.cambg.exists(): return
|
|
iw(s.cambg,opacity=i)
|
|
iw(s.cambg2,opacity=i)
|
|
teck(0.02,Call(s.fcam,i+a,a))
|
|
def rloop(s):
|
|
s.loop()
|
|
s.fixps()
|
|
s.hm('Replay',f'Version {Replay.VER} BETA',s.COL12,s.COL13)
|
|
def killui(s):
|
|
s.up = s.camon = False
|
|
[_.delete() for _ in s.trash()]
|
|
s.kids.clear()
|
|
s.camkids.clear()
|
|
def trash(s):
|
|
return s.kids+s.camkids
|
|
def kek(s):
|
|
if getattr(s,'kekbusy',0): return
|
|
s.kekbusy = True
|
|
if getattr(s,'tbye',0) and getattr(s,'frbro',0):
|
|
s.frbro = s.tbye = False
|
|
s.okt = None
|
|
s.nah = b = not s.nah
|
|
otw(s.kekt,text=s.tex[b])
|
|
if b:
|
|
teck(0.2,lambda:obw(s.kekb,texture=gt('empty')))
|
|
s.fkek(0.4,-0.05)
|
|
s.killui()
|
|
else:
|
|
obw(s.kekb,texture=gt('white'))
|
|
s.fkek(0,0.05)
|
|
s.mkui()
|
|
s.pro()
|
|
teck(0.21,Call(setattr,s,'kekbusy',0))
|
|
def fkek(s,i=0,a=0.1):
|
|
if i > 0.4 or i < 0: return
|
|
if not s.bg.exists(): return
|
|
iw(s.bg,opacity=i)
|
|
teck(0.02,Call(s.fkek,i+a,a))
|
|
def hm(s,t1,t2,c1,c2):
|
|
if getattr(s,'tbye',0) and getattr(s,'frbro',0):
|
|
s.frbro = s.tbye = False
|
|
s.okt = None
|
|
iw(s.ok,color=c1)
|
|
otw(s.ok2,text=t1,color=c2)
|
|
otw(s.ok3,text=t2,color=c2)
|
|
s.fok()
|
|
s.okt = tock(1.5,s.unhm)
|
|
def unhm(s):
|
|
s.fok(0.7,-0.1)
|
|
[otw(_,text='') for _ in [s.ok2,s.ok3] if _.exists()]
|
|
def fok(s,i=0,a=0.1):
|
|
if i > 0.7 or i < 0: return
|
|
if not s.ok.exists(): return
|
|
iw(s.ok,opacity=i)
|
|
teck(0.02,Call(s.fok,i+a,a))
|
|
def toggle(s,dry=False,shut=False):
|
|
if not dry: s.ps = not s.ps
|
|
t = cs(getattr(sc,['PAUSE','PLAY'][s.ps]+'_BUTTON'))
|
|
otw(s.tt,text=t)
|
|
if not dry:
|
|
if not shut: s.hm(['Resume','Pause'][s.ps],basename(s.path)+f' of {getsize(s.path)} bytes',s.COL6,s.COL7)
|
|
if s.ps:
|
|
s.stop()
|
|
PAUSE()
|
|
else:
|
|
s.play()
|
|
RESUME()
|
|
def fixps(s):
|
|
if not s.ps: return
|
|
s.toggle(shut=True)
|
|
teck(0.02,Call(s.toggle,shut=True))
|
|
def clock(s):
|
|
t = time()
|
|
r = t - s.rt
|
|
s.rt = t
|
|
s.rn += r * s.sp
|
|
def boost(s,i):
|
|
n = GET()+i
|
|
SET(n)
|
|
s.sp = 2**n
|
|
h = 'Snail Mode' if s.sp == 0.0625 else 'Slow Motion' if s.sp<1 else 'Quake Pro' if s.sp==16 else 'Fast Motion' if s.sp>1 else 'Normal Speed'
|
|
s.hm(h,f'Current exponent: x{s.sp}',s.COL2,s.COL3)
|
|
def play(s):
|
|
s.rt = time()
|
|
s.clock()
|
|
s.ptplay()
|
|
s.clt = tock(s.TICK,s.clock,repeat=True)
|
|
def stop(s):
|
|
s.clt = None
|
|
s.ptkill()
|
|
def ptkill(s):
|
|
s.pt = None
|
|
def ptplay(s):
|
|
s.pt = tock(s.TICK,s.pro,repeat=True)
|
|
def seek(s,i):
|
|
h = ['Forward by','Rewind by'][i==-1]
|
|
i = i * s.sp
|
|
i = (s.ds/20)*i
|
|
t = (s.rn-s.st)+i
|
|
if (t >= s.ds) or (t <= 0):
|
|
s.loop()
|
|
else:
|
|
s.st = s.rn-t
|
|
s.replay()
|
|
SEEK(t)
|
|
s.rt = time()
|
|
s.fixps()
|
|
i = abs(round(i,2))
|
|
s.hm('Seek',h+f" {i} second{['s',''][i==1]}",s.COL4,s.COL5)
|
|
def jump(s,p):
|
|
t = s.ds * p
|
|
s.st = s.rn-t
|
|
s.replay()
|
|
SEEK(t)
|
|
s.rt = time()
|
|
s.fixps()
|
|
def bye(s):
|
|
if getattr(s,'frbro',0): s._bye(); return
|
|
s.hm('Exit','Press again to confirm',s.COL0,s.COL1)
|
|
s.frbro = True
|
|
s.tbye = tock(1.5,Call(setattr,s,'frbro',False))
|
|
def _bye(s):
|
|
fade(0,time=0.75,endcall=Call(fade,1,time=0.75))
|
|
gs('deek').play()
|
|
BYE()
|
|
s.stop()
|
|
s.fockill()
|
|
s.tbye = None
|
|
SCM(False)
|
|
def pro(s):
|
|
t = s.rn-s.st
|
|
if s.rn-s.st >= s.ds: s.loop()
|
|
x,y = s.nbp
|
|
p = (t/s.ds)*s.px
|
|
try:
|
|
iw(s.nb,position=(x+p,y))
|
|
otw(s.ct,text=FOR(t))
|
|
except ReferenceError: pass
|
|
def replay(s):
|
|
SEEK(-10**10)
|
|
def loop(s):
|
|
s.st = s.rn = 0
|
|
s.replay()
|
|
bw = lambda s,label='',p=None,oac=None,pos=None,texture='white',**k: obw(
|
|
parent=p,
|
|
on_activate_call=oac,
|
|
position=pos,
|
|
label=label,
|
|
texture=gt(texture),
|
|
enable_sound=False,
|
|
**k
|
|
)
|
|
|
|
# Tools
|
|
BYE = lambda: app.classic.return_to_main_menu_session_gracefully(reset_ui=False)
|
|
BTW = lambda t: (gs('block').play() or 1) and push(t,color=(1,1,0))
|
|
GOS = lambda: gsw('overlay_stack')
|
|
FOR = lambda t: strftime('%H:%M:%S',gmtime(t))
|
|
SCL = lambda a,b,c=None: ((s:=app.ui_v1.uiscale), a if s is UIS.SMALL else b if s is UIS.MEDIUM else (c or b))[1]
|
|
RND = lambda t: type(t)([round(_,1) for _ in t])
|
|
|
|
# pybrp
|
|
Z = lambda _:[0]*_
|
|
G_FREQS = lambda:[
|
|
101342,9667,3497,1072,0,3793,*Z(2),2815,5235,*Z(3),3570,*Z(3),
|
|
1383,*Z(3),2970,*Z(2),2857,*Z(8),1199,*Z(30),
|
|
1494,1974,*Z(12),1351,*Z(122),1475,*Z(65)
|
|
]
|
|
CMD_NAMES=lambda:{0:'BaseTimeStep',1:'StepSceneGraph',2:'AddSceneGraph',3:'RemoveSceneGraph',4:'AddNode',5:'NodeOnCreate',6:'SetForegroundScene',7:'RemoveNode',8:'AddMaterial',9:'RemoveMaterial',10:'AddMaterialComponent',11:'AddTexture',12:'RemoveTexture',13:'AddMesh',14:'RemoveMesh',15:'AddSound',16:'RemoveSound',17:'AddCollisionMesh',18:'RemoveCollisionMesh',19:'ConnectNodeAttribute',20:'NodeMessage',21:'SetNodeAttrFloat',22:'SetNodeAttrInt32',23:'SetNodeAttrBool',24:'SetNodeAttrFloats',25:'SetNodeAttrInt32s',26:'SetNodeAttrString',27:'SetNodeAttrNode',28:'SetNodeAttrNodeNull',29:'SetNodeAttrNodes',30:'SetNodeAttrPlayer',31:'SetNodeAttrPlayerNull',32:'SetNodeAttrMaterials',33:'SetNodeAttrTexture',34:'SetNodeAttrTextureNull',35:'SetNodeAttrTextures',36:'SetNodeAttrSound',37:'SetNodeAttrSoundNull',38:'SetNodeAttrSounds',39:'SetNodeAttrMesh',40:'SetNodeAttrMeshNull',41:'SetNodeAttrMeshes',42:'SetNodeAttrCollisionMesh',43:'SetNodeAttrCollisionMeshNull',44:'SetNodeAttrCollisionMeshes',45:'PlaySoundAtPosition',46:'PlaySound',47:'EmitBGDynamics',48:'EndOfFile',49:'DynamicsCorrection',50:'ScreenMessageBottom',51:'ScreenMessageTop',52:'AddData',53:'RemoveData',54:'CameraShake'}
|
|
class _H:
|
|
class _N:
|
|
def __init__(self):
|
|
self.l,self.r,self.p,self.f=-1,-1,0,0
|
|
def __init__(self):
|
|
gf,self.nodes=G_FREQS(),[self._N()for _ in range(511)]
|
|
for i in range(256):self.nodes[i].f=gf[i]
|
|
nc=256
|
|
while nc<511:
|
|
s1,s2=-1,-1
|
|
i=0
|
|
while self.nodes[i].p!=0:i+=1
|
|
s1=i;i+=1
|
|
while self.nodes[i].p!=0:i+=1
|
|
s2=i;i+=1
|
|
while i<nc:
|
|
if self.nodes[i].p==0:
|
|
if self.nodes[s1].f>self.nodes[s2].f:
|
|
if self.nodes[i].f<self.nodes[s1].f:s1=i
|
|
elif self.nodes[i].f<self.nodes[s2].f:s2=i
|
|
i+=1
|
|
self.nodes[nc].f=self.nodes[s1].f+self.nodes[s2].f
|
|
self.nodes[s1].p=self.nodes[s2].p=nc-255
|
|
self.nodes[nc].r,self.nodes[nc].l=s1,s2
|
|
nc+=1
|
|
def decompress(self,src):
|
|
if not src:return b''
|
|
rem,comp=src[0]&15,src[0]>>7
|
|
if not comp:return src
|
|
out,ptr,l=bytearray(),src[1:],len(src)
|
|
bl=((l-1)*8)-rem;bit=0
|
|
while bit<bl:
|
|
m_bit=(ptr[bit>>3]>>(bit&7))&1;bit+=1
|
|
if m_bit:
|
|
n=510
|
|
while n>=256:
|
|
if bit>=bl:raise ValueError("Incomplete Huffman code")
|
|
p_bit=(ptr[bit>>3]>>(bit&7))&1;bit+=1
|
|
n=self.nodes[n].l if p_bit==0 else self.nodes[n].r
|
|
out.append(n)
|
|
else:
|
|
if bit+8>bl:break
|
|
bi,b_in_b=bit>>3,bit&7
|
|
val=ptr[bi]if b_in_b==0 else(ptr[bi]>>b_in_b)|(ptr[bi+1]<<(8-b_in_b))
|
|
out.append(val&255);bit+=8
|
|
return bytes(out)
|
|
def GMS(_h, brp_path, par):
|
|
total_ms = 0
|
|
with open(brp_path, 'rb') as f:
|
|
f.seek(0,2)
|
|
par[1] = f.tell()
|
|
f.seek(6)
|
|
while True:
|
|
if par: par[0] = f.tell()
|
|
b_data = f.read(1)
|
|
if not b_data:
|
|
break
|
|
b1, comp_len = b_data[0], 0
|
|
if b1 < 254:
|
|
comp_len = b1
|
|
elif b1 == 254:
|
|
comp_len = int.from_bytes(f.read(2), 'little')
|
|
else: # 255
|
|
comp_len = int.from_bytes(f.read(4), 'little')
|
|
if comp_len == 0:
|
|
continue
|
|
raw_msg = _h.decompress(f.read(comp_len))
|
|
if not raw_msg or raw_msg[0] != 1:
|
|
continue
|
|
sub_off = 1
|
|
while sub_off < len(raw_msg):
|
|
try:
|
|
sub_size = int.from_bytes(raw_msg[sub_off:sub_off+2], 'little')
|
|
except IndexError:
|
|
break
|
|
except ValueError:
|
|
break
|
|
sub_data = raw_msg[sub_off+2:sub_off+2+sub_size]
|
|
if sub_data and sub_data[0] == 0:
|
|
total_ms += sub_data[1]
|
|
sub_off += 2 + sub_size
|
|
if par: par[0] = par[1]
|
|
return total_ms
|
|
|
|
# brobord collide grass
|
|
# ba_meta require api 9
|
|
# ba_meta export babase.Plugin
|
|
class byBordd(Plugin):
|
|
def __init__(s):
|
|
from bauiv1lib.ingamemenu import InGameMenuWindow as m
|
|
a = '_refresh_in_game'; o = getattr(m,a)
|
|
setattr(m,a,lambda v,*a,**k:(s.mk(v),o(v,*a,**k))[1])
|
|
from bauiv1lib.watch import WatchWindow as n
|
|
b = '__init__'; p = getattr(n,b)
|
|
setattr(n,b,lambda v,*a,**k:(p(v,*a,**k),s.mk(v,1))[0])
|
|
def mk(s,v,i=0):
|
|
if i:
|
|
x = v._width/2+SCL(v._scroll_width*-0.5+93,0)+100
|
|
y = v.yoffs-SCL(63,10)-25
|
|
s.b = Replay.bw(
|
|
Replay,
|
|
p=v._root_widget,
|
|
label='Replay',
|
|
pos=(x,y) if i else (-70,0),
|
|
icon=gt('replayIcon'),
|
|
iconscale=1.6 if i else 0.8,
|
|
size=(140,50) if i else (90,35),
|
|
oac=lambda:Replay(source=s.b)
|
|
)
|
|
|