mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
Added plugins
This commit is contained in:
parent
0bffcc0a67
commit
38417928cd
9 changed files with 3791 additions and 31 deletions
|
|
@ -55,11 +55,11 @@
|
|||
},
|
||||
"sandbox": {
|
||||
"description": "Spawn, control and bots, change music, add teams, spawn objects, change game values in real time, and much more!",
|
||||
"external_url": "",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "thehero2012008@gmail.com",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
|
|
@ -86,15 +86,16 @@
|
|||
},
|
||||
"updown": {
|
||||
"description": "Adds UP and DOWN buttons in party window to recall messages in chat.",
|
||||
"external_url": "",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "thehero2012008@gmail.com",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.1.4": null,
|
||||
"1.1.3": {
|
||||
"api_version": 9,
|
||||
"commit_sha": "e604a3c",
|
||||
|
|
@ -128,12 +129,12 @@
|
|||
}
|
||||
},
|
||||
"rejoin": {
|
||||
"description": "Adds a button in pause menu, which rejoins current server once clicked! if didn't work, just click again and again. if still, then party is full.",
|
||||
"external_url": "",
|
||||
"description": "Deprecated - Better use Power plugin. Adds a button in pause menu, which rejoins current server once clicked! if didn't work, just click again and again. if still, then party is full.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "thehero2012008@gmail.com",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
|
|
@ -164,17 +165,108 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"topmsg": {
|
||||
"description": "When chat is muted, see new chat messages on top right! (like kill logs)",
|
||||
"external_url": "",
|
||||
"power": {
|
||||
"description": "With one click. Experimental. Adds a dev console tab with some features I find useful. Power is mainly focused on the multiplayer side. Can be considered a good tool to have around.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "thehero2012008@gmail.com",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"2.7": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugtools": {
|
||||
"description": "Live Plugin Action. Beta. Adds a dev console tab for plugin management. For full features, read the first lines in the py file, or look in the source.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.5": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"camera": {
|
||||
"description": "Say cheese. Adds a button to pause menu. Camera is advanced Camera allows you to change camera position and target with a very easy graphical visualization of how it would look like.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"finder": {
|
||||
"description": "Find anyone. Experimental. Useful if you are looking for someone, or just messing around. For full features, either check first lines of py file, or check source. Combine with Power plugin for better control.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": {
|
||||
"description": "Where it's going to be. Experimental. Path tries to predict the next position of bomb. Path relies on velocity to operate. Optionally pass spaz node (holder) to assist prediction.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.0": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"description": "Simple replay player. Experimental. Adds a button to pause menu and watch menu. For full features, either read first lines of py file, or check source.",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.5": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"topmsg": {
|
||||
"description": "When chat is muted, see new chat messages on top right! (like kill logs)",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
"versions": {
|
||||
"1.1.2": null,
|
||||
"1.1.1": {
|
||||
"api_version": 9,
|
||||
"commit_sha": "e604a3c",
|
||||
|
|
@ -197,11 +289,11 @@
|
|||
},
|
||||
"sorry": {
|
||||
"description": "Send a random sorry to chat, preventing revenge attempts from teammates you kill by mistake.",
|
||||
"external_url": "",
|
||||
"external_url": "https://brobordd.github.io/byBordd",
|
||||
"authors": [
|
||||
{
|
||||
"name": "BrotherBoard",
|
||||
"email": "thehero2012008@gmail.com",
|
||||
"email": "brobordd@gmail.com",
|
||||
"discord": "BrotherBoard"
|
||||
}
|
||||
],
|
||||
|
|
@ -2140,4 +2232,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
586
plugins/utilities/camera.py
Executable file
586
plugins/utilities/camera.py
Executable file
|
|
@ -0,0 +1,586 @@
|
|||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Bug? Feedback? Telegram >> @GalaxyA14user
|
||||
|
||||
"""
|
||||
Camera v1.0 - Say cheese.
|
||||
|
||||
Adds a button to pause menu. Camera is advanced
|
||||
Camera allows you to change camera position and
|
||||
target with a very easy graphical visualization
|
||||
of how it would look like.
|
||||
"""
|
||||
|
||||
from _babase import (
|
||||
get_display_resolution as GDR,
|
||||
clipboard_is_supported as CIS,
|
||||
set_camera_position as SCP,
|
||||
clipboard_set_text as COPY,
|
||||
set_camera_manual as SSCM,
|
||||
set_camera_target as SCT
|
||||
)
|
||||
from bascenev1 import (
|
||||
get_foreground_host_activity as ga,
|
||||
OutOfBoundsMessage,
|
||||
gettexture as gbt,
|
||||
getsound as gbs,
|
||||
timer as tick,
|
||||
Material,
|
||||
getmesh,
|
||||
newnode,
|
||||
animate,
|
||||
emitfx
|
||||
)
|
||||
from bauiv1 import (
|
||||
get_special_widget as gsw,
|
||||
containerwidget as cw,
|
||||
screenmessage as push,
|
||||
buttonwidget as bw,
|
||||
imagewidget as iw,
|
||||
textwidget as tw,
|
||||
gettexture as gt,
|
||||
apptimer as teck,
|
||||
getsound as gs,
|
||||
app as APP
|
||||
)
|
||||
from bauiv1lib.ingamemenu import InGameMenuWindow as igm
|
||||
from babase import Plugin, InputType as IT
|
||||
from math import sqrt, dist
|
||||
|
||||
class Camera:
|
||||
__doc__ = 'A simple camera.'
|
||||
__ins__ = None
|
||||
__lst__ = None
|
||||
__yes__ = False
|
||||
def __init__(s) -> None:
|
||||
c = s.__class__
|
||||
if c.__yes__:
|
||||
note('Stopped camera!',True)
|
||||
c.__ins__.done(talk=False)
|
||||
return
|
||||
c.__ins__ = s
|
||||
c.__yes__ = True
|
||||
if c.__lst__: SCM(False)
|
||||
s.stage = 0
|
||||
p = (0,1,0)
|
||||
s.tex = 'achievementCrossHair'
|
||||
s.kids = []
|
||||
s.okay = []
|
||||
with ga().context:
|
||||
s.M = Material()
|
||||
s.M.add_actions(
|
||||
conditions=(('they_are_older_than', 0)),
|
||||
actions=(
|
||||
('modify_part_collision', 'collide', False),
|
||||
('modify_part_collision', 'physical', False),
|
||||
('modify_part_collision', 'friction', 0),
|
||||
('modify_part_collision', 'stiffness', 0),
|
||||
('modify_part_collision', 'damping', 0)
|
||||
)
|
||||
)
|
||||
n = newnode(
|
||||
'prop',
|
||||
delegate=s,
|
||||
attrs={
|
||||
'mesh': getmesh('tnt'),
|
||||
'color_texture': gbt(s.tex),
|
||||
'body': 'crate',
|
||||
'reflection': 'soft',
|
||||
'density': 4.0,
|
||||
'reflection_scale': [1.5],
|
||||
'shadow_size': 0.6,
|
||||
'position': p,
|
||||
'gravity_scale': 0,
|
||||
'materials': [s.M],
|
||||
'is_area_of_interest': True
|
||||
}
|
||||
)
|
||||
tick(0.15, animate(n,'mesh_scale',{0:2,0.1:0.5}).delete)
|
||||
gbs('powerup01').play(position=p)
|
||||
s.step = 0.01
|
||||
s.node = n
|
||||
s.wait = 0.001
|
||||
s.mode = 4
|
||||
s.llr = s.lud = 0.0
|
||||
s.overlay = Overlay()
|
||||
LN({
|
||||
'UP_DOWN': lambda a: s.manage(a),
|
||||
'LEFT_RIGHT': lambda a: s.manage(a,1),
|
||||
'PICK_UP_PRESS': lambda: s.start(2),
|
||||
'JUMP_PRESS': lambda: s.start(0),
|
||||
'PICK_UP_RELEASE': lambda: s.stop(2),
|
||||
'JUMP_RELEASE': lambda: s.stop(0),
|
||||
'BOMB_PRESS': s.done,
|
||||
'BOMB_RELEASE': lambda: s.overlay.release(1),
|
||||
'PUNCH_PRESS': s.mark,
|
||||
'PUNCH_RELEASE': lambda: s.overlay.release(3),
|
||||
})
|
||||
s.move()
|
||||
"""Write a tip"""
|
||||
def tip(s,t,p,h='left',b=True):
|
||||
n = newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'in_world': True,
|
||||
'scale': 0.01,
|
||||
'flatness': 1,
|
||||
'color': (1,1,1),
|
||||
'shadow': 1.0,
|
||||
'position': p,
|
||||
'text': t,
|
||||
'h_align': h
|
||||
}
|
||||
)
|
||||
if b: s.kids.append(n)
|
||||
return n
|
||||
"""Create a dot"""
|
||||
def dot(s,p,b=True,tex='black'):
|
||||
n = newnode(
|
||||
'prop',
|
||||
delegate=s,
|
||||
attrs={
|
||||
'mesh': getmesh('tnt'),
|
||||
'color_texture': gbt(tex),
|
||||
'body': 'crate',
|
||||
'mesh_scale': 0.1,
|
||||
'position': p,
|
||||
'gravity_scale': 0,
|
||||
'materials': [s.M],
|
||||
}
|
||||
)
|
||||
if b: s.kids.append(n)
|
||||
return n
|
||||
"""Draw a line"""
|
||||
def line(s,p1,p2,i=2,tex='black'):
|
||||
x1,y1,z1 = p1
|
||||
x2,y2,z2 = p2
|
||||
n = dist(p1,p2)*i
|
||||
for i in range(1,int(n+1)):
|
||||
t = i/n
|
||||
x = x1+t*(x2-x1)
|
||||
y = y1+t*(y2-y1)
|
||||
z = z1+t*(z2-z1)
|
||||
s.kids.append(s.dot((x,y,z),tex=tex))
|
||||
"""Mark"""
|
||||
def mark(s):
|
||||
if not s.stage:
|
||||
s.stage = 1
|
||||
p = s.getpos()
|
||||
s.p1 = (p[0]-0.01,p[1],p[2])
|
||||
s.okay.append(s.dot(s.p1,b=False))
|
||||
s.okay.append(s.tip(f'Camera position\n{tuple([round(i,2) for i in s.p1])}',s.p1,b=False))
|
||||
else:
|
||||
[i.delete() for i in s.kids]
|
||||
s.kids.clear()
|
||||
p2 = s.p2 = s.getpos()
|
||||
|
||||
r = GDR()
|
||||
w = r[0]/r[1]
|
||||
h = 1
|
||||
|
||||
vd = sub(p2, s.p1)
|
||||
vd_n = norm(vd)
|
||||
|
||||
t_up = (0, 1, 0)
|
||||
r_v = cross(vd_n, t_up)
|
||||
r_v_n = norm(r_v)
|
||||
|
||||
up_v = cross(r_v_n, vd_n)
|
||||
up_v_n = norm(up_v)
|
||||
|
||||
hw = w / 2.0
|
||||
hh = h / 2.0
|
||||
|
||||
tr = add(p2, add(scale(r_v_n, hw), scale(up_v_n, hh)))
|
||||
tl = add(p2, add(scale(r_v_n, -hw), scale(up_v_n, hh)))
|
||||
br = add(p2, add(scale(r_v_n, hw), scale(up_v_n, -hh)))
|
||||
bl = add(p2, add(scale(r_v_n, -hw), scale(up_v_n, -hh)))
|
||||
|
||||
s.line(s.p1, tr)
|
||||
s.line(s.p1, tl)
|
||||
s.line(s.p1, br)
|
||||
s.line(s.p1, bl)
|
||||
|
||||
m = 4
|
||||
j = {'tex':'crossOutMask'}
|
||||
s.line(tr, tl, m, **j)
|
||||
s.line(tl, bl, m, **j)
|
||||
s.line(bl, br, m, **j)
|
||||
s.line(br, tr, m, **j)
|
||||
|
||||
s.tip(f'Your display\n{r[0]}x{r[1]} px\n{tuple([round(i,2) for i in p2])}',tr,'right')
|
||||
s.stage = 2
|
||||
s.overlay.press(3)
|
||||
tick(0.25, animate(s.node,'mesh_scale',{0:0.5,0.1:0.2,0.2:0.5}).delete)
|
||||
gbs('gunCocking').play(position=s.node.position)
|
||||
"""Handle events"""
|
||||
def handlemessage(s, m):
|
||||
if isinstance(m, OutOfBoundsMessage):
|
||||
p = s.getpos()
|
||||
gbs('shatter').play(position=p)
|
||||
emitfx(
|
||||
scale=1,
|
||||
count=30,
|
||||
spread=0.1,
|
||||
position=p,
|
||||
chunk_type='ice'
|
||||
)
|
||||
s.destroy()
|
||||
note('Out of bounds!')
|
||||
"""Destroy"""
|
||||
def destroy(s):
|
||||
with ga().context:
|
||||
n = s.node
|
||||
s.mode = 2
|
||||
n.delete()
|
||||
s.reset()
|
||||
"""Reset input"""
|
||||
def reset(s):
|
||||
s.__class__.__yes__ = False
|
||||
me = getme()
|
||||
if not me: return
|
||||
me.resetinput()
|
||||
with ga().context: me.actor.connect_controls_to_player()
|
||||
[i.delete() for i in (s.kids+s.okay)]
|
||||
"""Manage movement"""
|
||||
def manage(s,a,lr=0):
|
||||
if lr: s.llr = a; return
|
||||
s.lud = a
|
||||
"""Move"""
|
||||
def move(s):
|
||||
m = getme(1)
|
||||
if (not m) or m._dead: s.destroy()
|
||||
try: p = s.getpos()
|
||||
except:
|
||||
s.overlay.destroy()
|
||||
return
|
||||
s.setpos((p[0]+s.llr*s.step,p[1],p[2]-s.lud*s.step))
|
||||
s.overlay.up(*p,s.llr,s.lud)
|
||||
SCT(*p)
|
||||
teck(s.wait,s.move)
|
||||
"""Start elevating"""
|
||||
def start(s,i):
|
||||
s.overlay.press(i)
|
||||
s.mode = i
|
||||
s.loop(i)
|
||||
"""Keep elevating"""
|
||||
def loop(s,i):
|
||||
if s.mode != i: return
|
||||
try: p = list(s.node.position)
|
||||
except: return
|
||||
p[1] += s.step if i else -s.step
|
||||
s.node.position = tuple(p)
|
||||
teck(s.wait, lambda: s.loop(i))
|
||||
"""Stop elevating"""
|
||||
def stop(s,i):
|
||||
s.overlay.release(i)
|
||||
s.mode = 4
|
||||
"""Get position"""
|
||||
def getpos(s):
|
||||
return s.node.position
|
||||
"""Set position"""
|
||||
def setpos(s,p):
|
||||
s.node.position = p
|
||||
"""Done"""
|
||||
def done(s,talk=True):
|
||||
s.overlay.press(1)
|
||||
s.overlay.destroy()
|
||||
try: p = s.node.position
|
||||
except: return
|
||||
with ga().context:
|
||||
gbs('laser').play(position=p)
|
||||
tick(0.2,animate(s.node,'mesh_scale',{0:0.5,0.08:1,0.2:0}).delete)
|
||||
tick(0.2,s.node.delete)
|
||||
s.reset()
|
||||
if s.stage > 1 and talk:
|
||||
SCM(True)
|
||||
SCP(*s.p1)
|
||||
SCT(*s.p2)
|
||||
var('lp1',s.p1)
|
||||
var('lp2',s.p2)
|
||||
nice('Applied!')
|
||||
elif talk:
|
||||
note('Incomplete camera setup\nNo changes applied.')
|
||||
if s.__class__.__ins__ == s: s.__class__.__ins__ = None
|
||||
|
||||
"""Controls overlay"""
|
||||
class Overlay:
|
||||
__lst__ = None
|
||||
"""Place nodes"""
|
||||
def __init__(s):
|
||||
s.__class__.__lst__ = str(ga())
|
||||
s.colors = [
|
||||
[(0.2,0.6,0.2),(0.4,1,0.4)],
|
||||
[(0.6,0,0),(1,0,0)],
|
||||
[(0.2,0.6,0.6),(0.4,1,1)],
|
||||
[(0.6,0.6,0.2),(1,1,0.4)],
|
||||
[(0.3,0.23,0.5),(0.2,0.13,0.3)]
|
||||
]
|
||||
s.pics = []
|
||||
s.texts = []
|
||||
s.pos = []
|
||||
s.nub = []
|
||||
s.old = [0,0,0]
|
||||
s.dead = False
|
||||
with ga().context:
|
||||
for i in range(4):
|
||||
j = ['Jump','Bomb','PickUp','Punch'][i]
|
||||
k = [600,650,600,550][i]
|
||||
l = [170,220,270,220][i]
|
||||
c = s.colors[i][0]
|
||||
n = newnode(
|
||||
'image',
|
||||
attrs={
|
||||
'texture': gbt('button'+j),
|
||||
'absolute_scale': True,
|
||||
'position': (k,l),
|
||||
'scale': (60,60),
|
||||
'color': c
|
||||
}
|
||||
)
|
||||
s.pics.append(n)
|
||||
j = ['Down','Done','Up','Mark'][i]
|
||||
k = [600,680,600,515][i]
|
||||
l = [115,220,325,220][i]
|
||||
h = ['center','left','center','right'][i]
|
||||
v = ['bottom','center','top','center'][i]
|
||||
n = newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'text': j,
|
||||
'position': (k,l),
|
||||
'color': c,
|
||||
'h_align': h,
|
||||
'v_align': v
|
||||
}
|
||||
)
|
||||
s.texts.append(n)
|
||||
for i in range(3):
|
||||
c = s.colors[[1,0,2][i]][0]
|
||||
n = newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'text': '0',
|
||||
'position': (640,155-30*i),
|
||||
'color': c,
|
||||
'h_align': 'left'
|
||||
}
|
||||
)
|
||||
s.pos.append(n)
|
||||
s.np = (790,140)
|
||||
for i in [0,1]:
|
||||
j = [110,60][i]
|
||||
n = newnode(
|
||||
'image',
|
||||
attrs={
|
||||
'texture': gbt('nub'),
|
||||
'absolute_scale': True,
|
||||
'position': s.np,
|
||||
'scale': (j,j),
|
||||
'color': s.colors[4][i]
|
||||
}
|
||||
)
|
||||
s.nub.append(n)
|
||||
s.fade()
|
||||
"""Color overlays"""
|
||||
def set(s,i,c):
|
||||
s.pics[i].color = s.texts[i].color = c
|
||||
"""Color position"""
|
||||
def pset(s,i,c):
|
||||
s.pos[i].color = c
|
||||
"""Simulate pressed"""
|
||||
def press(s,i):
|
||||
s.set(i,s.colors[i][1])
|
||||
s.pics[i].opacity = 1.0
|
||||
"""Simulate released"""
|
||||
def release(s,i):
|
||||
s.set(i,s.colors[i][0])
|
||||
s.pics[i].opacity = 0.7
|
||||
"""Get all nodes"""
|
||||
def nodes(s):
|
||||
return s.pics+s.texts+s.pos+s.nub
|
||||
"""Update position"""
|
||||
def up(s,x,y,z,lr,ud):
|
||||
new = [x,y,z]
|
||||
for i in range(3):
|
||||
c = s.colors[[1,0,2][i]]
|
||||
if s.old[i] == new[i]: s.pset(i,c[0]); continue
|
||||
t = s.pos[i]
|
||||
t.text = str(round(new[i],5))
|
||||
s.pset(i,c[1])
|
||||
s.old = new
|
||||
[setattr(s.nub[i],'opacity',[[0.5,0.2],[0.7,0.3]][bool(lr or ud)][i]) for i in [0,1]]
|
||||
p = s.np
|
||||
m = sqrt(lr**2+ud**2) or 1
|
||||
d = 25*min(sqrt(lr**2+ud**2),1)
|
||||
lr /= m
|
||||
ud /= m
|
||||
s.nub[1].position = (p[0]+lr*d,p[1]+ud*d)
|
||||
"""Fade"""
|
||||
def fade(s,i=0):
|
||||
if str(ga()) != s.__class__.__lst__: return
|
||||
mem = s.nodes()
|
||||
[tick(1, animate(n,'opacity',{0:i,0.5:abs(i-0.7)}).delete) for n in mem]
|
||||
"""Destroy overlay"""
|
||||
def destroy(s):
|
||||
if s.dead: return
|
||||
s.dead = True
|
||||
with ga().context:
|
||||
tick(0.2,lambda:s.fade(0.7))
|
||||
tick(2,lambda: [n.delete() for n in s.nodes()])
|
||||
|
||||
# Mini tools
|
||||
note = lambda t, b=False: (push(t,color=(1,1,0)),gs('block').play() if b else None)
|
||||
nice = lambda t: (push(t,color=(0,1,0)),gs('dingSmallHigh').play())
|
||||
SCM = lambda b: (setattr(Camera,'__lst__',b),SSCM(b))
|
||||
scale = lambda v,s: (v[0]*s,v[1]*s,v[2]*s)
|
||||
cross = lambda a,b: (a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0])
|
||||
sub = lambda a,b: (a[0]-b[0],a[1]-b[1],a[2]-b[2])
|
||||
add = lambda a,b: (a[0]+b[0],a[1]+b[1],a[2]+b[2])
|
||||
def getme(actor=0):
|
||||
for p in ga().players:
|
||||
if p.sessionplayer.inputdevice.client_id == -1:
|
||||
return p.actor if actor else p
|
||||
def LN(d): me = getme(); [me.assigninput(getattr(IT,k), d[k]) for k in d]
|
||||
def RESUME():
|
||||
u = APP.ui_v1
|
||||
c = APP.classic
|
||||
c.resume()
|
||||
u.clear_main_window()
|
||||
[z() for z in c.main_menu_resume_callbacks]
|
||||
c.main_menu_resume_callbacks.clear()
|
||||
def norm(v):
|
||||
a,b,c = v
|
||||
l = sqrt(a**2+b**2+c**2)
|
||||
return (0, 0, 0) if l == 0 else (a/l,b/l,c/l)
|
||||
def var(s,v=None):
|
||||
c = APP.config
|
||||
s = 'cam_'+s
|
||||
if v is None: return c.get(s,v)
|
||||
c[s] = v
|
||||
c.commit()
|
||||
|
||||
# brobord collide grass
|
||||
# ba_meta require api 9
|
||||
# ba_meta export babase.Plugin
|
||||
class byBordd(Plugin):
|
||||
has_settings_ui = lambda s: True
|
||||
show_settings_ui = lambda s, src: s.ui(source=src)
|
||||
col = (0.18,0.18,0.18)
|
||||
def __init__(s):
|
||||
o = igm._refresh_in_game
|
||||
def e(f,*a,**k):
|
||||
r = o(f,*a,**k)
|
||||
b = bw(
|
||||
label='',
|
||||
size=(90,40),
|
||||
button_type='square',
|
||||
parent=f._root_widget,
|
||||
color=(0.18,0.18,0.18),
|
||||
position=(f._width-20,0),
|
||||
)
|
||||
bw(b,on_activate_call=lambda:s.ui(source=b,main=True))
|
||||
iw(
|
||||
size=(40,40),
|
||||
texture=gt('tv'),
|
||||
parent=f._root_widget,
|
||||
position=(f._width-20,5)
|
||||
)
|
||||
tw(
|
||||
maxwidth=50,
|
||||
text='Camera',
|
||||
h_align='left',
|
||||
parent=f._root_widget,
|
||||
position=(f._width+15,0)
|
||||
)
|
||||
return r
|
||||
igm._refresh_in_game = e
|
||||
"""The UI"""
|
||||
def ui(s,source=None,main=False):
|
||||
s.main = main
|
||||
off = source.get_screen_space_center() if source else (0,0)
|
||||
w = cw(
|
||||
color=s.col,
|
||||
size=(350,305),
|
||||
stack_offset=off,
|
||||
transition='in_scale',
|
||||
parent=gsw('overlay_stack'),
|
||||
scale_origin_stack_offset=off
|
||||
)
|
||||
s.back = lambda b=True: (cw(w,transition=['out_right','out_scale'][bool(source) and b]),gs('swish').play() if b else None)
|
||||
cw(w,on_outside_click_call=s.back)
|
||||
b = Camera.__yes__
|
||||
t = [
|
||||
('Camera is ready!',(0,1,1)),
|
||||
('Camera is running!',(0,1,0)),
|
||||
][b]
|
||||
tw(
|
||||
parent=w,
|
||||
text=t[0],
|
||||
scale=1.5,
|
||||
color=t[1],
|
||||
h_align='center',
|
||||
position=(155,250)
|
||||
)
|
||||
for i in range(4):
|
||||
j = [
|
||||
('3D Camera mapper',s.start),
|
||||
('Last mapped config',s.load),
|
||||
('Last dev command',s.copy),
|
||||
('Reset all settings',s.reset)
|
||||
][i]
|
||||
tw(
|
||||
parent=w,
|
||||
text=j[0],
|
||||
maxwidth=195,
|
||||
position=(20,30+55*i)
|
||||
)
|
||||
k = [
|
||||
(['Start','Stop'][b],'cursor'),
|
||||
('Load','achievementOutline'),
|
||||
('Copy','file'),
|
||||
('Reset','replayIcon')
|
||||
][i]
|
||||
bw(
|
||||
parent=w,
|
||||
label=k[0],
|
||||
color=s.col,
|
||||
size=(120,50),
|
||||
icon=gt(k[1]),
|
||||
enable_sound=not i,
|
||||
textcolor=(1,1,1),
|
||||
button_type='square',
|
||||
on_activate_call=j[1],
|
||||
position=(220,20+55*i)
|
||||
)
|
||||
"""Gather last"""
|
||||
def gather(s):
|
||||
return var('lp1'),var('lp2')
|
||||
"""Reset"""
|
||||
def reset(s):
|
||||
SCM(False)
|
||||
nice('Resetored original settings!')
|
||||
"""Copy last"""
|
||||
def copy(s):
|
||||
if not CIS(): note('Unsupported!',True); return
|
||||
g = s.gather()
|
||||
if not g[1]: note('Apply something first!',True); return
|
||||
g = [tuple([round(i,2) for i in j]) for j in g]
|
||||
COPY(f'from _babase import set_camera_manual as SCM, set_camera_target as SCT, set_camera_position as SCP; SCM(True); SCP(*{g[0]}); SCT(*{g[1]})')
|
||||
nice('Copied command!\nPaste it in dev console anytime to load config!')
|
||||
"""Load last"""
|
||||
def load(s):
|
||||
g = s.gather()
|
||||
if not g[1]: note('Apply something first!',True); return
|
||||
if Camera.__yes__: note('Stop camera first!',True); return
|
||||
SCM(True)
|
||||
SCP(*g[0])
|
||||
SCT(*g[1])
|
||||
nice('Loaded last config!')
|
||||
"""Start camera"""
|
||||
def start(s):
|
||||
a = ga()
|
||||
if not a: note('Only mapping requires you to be the host!\nYou still can load previous config though',True); return
|
||||
if not getme(): note('Join the game first!',True); return
|
||||
s.back(False)
|
||||
RESUME() if s.main else None
|
||||
with a.context: Camera()
|
||||
471
plugins/utilities/finder.py
Executable file
471
plugins/utilities/finder.py
Executable file
|
|
@ -0,0 +1,471 @@
|
|||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Intended for personal use only
|
||||
# Bug? Feedback? Telegram >> GalaxyA14user
|
||||
|
||||
"""
|
||||
Finder v1.0 - Find anyone
|
||||
|
||||
Experimental. Feedback is appreciated.
|
||||
Useful if you are looking for someone, or just messing around.
|
||||
|
||||
Features:
|
||||
- Fetch servers: Pings all servers, then sorts them by lowest
|
||||
- Ability to cycle through x servers to collect users
|
||||
- Ability to connect to servers by player name there
|
||||
|
||||
Combine with Power plugin for better control.
|
||||
"""
|
||||
|
||||
from socket import socket, SOCK_DGRAM
|
||||
from random import uniform as uf
|
||||
from babase import Plugin, app
|
||||
from threading import Thread
|
||||
from time import time, sleep
|
||||
from bauiv1 import (
|
||||
get_ip_address_type as IPT,
|
||||
clipboard_set_text as COPY,
|
||||
get_special_widget as zw,
|
||||
containerwidget as ocw,
|
||||
screenmessage as push,
|
||||
buttonwidget as obw,
|
||||
scrollwidget as sw,
|
||||
imagewidget as iw,
|
||||
textwidget as tw,
|
||||
gettexture as gt,
|
||||
apptimer as teck,
|
||||
getsound as gs,
|
||||
getmesh as gm,
|
||||
Call
|
||||
)
|
||||
from bascenev1 import (
|
||||
disconnect_from_host as BYE,
|
||||
connect_to_party as CON,
|
||||
protocol_version as PT,
|
||||
get_game_roster as GGR
|
||||
)
|
||||
|
||||
class Finder:
|
||||
COL1 = (0,0.3,0.3)
|
||||
COL2 = (0,0.55,0.55)
|
||||
COL3 = (0,0.7,0.7)
|
||||
COL4 = (0,1,1)
|
||||
COL5 = (1,1,0)
|
||||
MAX = 0.3
|
||||
TOP = 15
|
||||
VER = '1.0'
|
||||
MEM = []
|
||||
BST = []
|
||||
SL = None
|
||||
def __init__(s,src):
|
||||
s.thr = []
|
||||
s.ikids = []
|
||||
s.busy = False
|
||||
s.s1 = s.snd('powerup01')
|
||||
c = s.__class__
|
||||
# parent
|
||||
z = (460,400)
|
||||
s.p = cw(
|
||||
scale_origin_stack_offset=src.get_screen_space_center(),
|
||||
size=z,
|
||||
oac=s.bye
|
||||
)[0]
|
||||
# footing
|
||||
sw(
|
||||
parent=s.p,
|
||||
size=z,
|
||||
border_opacity=0
|
||||
)
|
||||
# fetch
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Fetch Servers',
|
||||
color=s.COL4,
|
||||
position=(19,359)
|
||||
)
|
||||
bw(
|
||||
parent=s.p,
|
||||
position=(360,343),
|
||||
size=(80,39),
|
||||
label='Fetch',
|
||||
color=s.COL2,
|
||||
textcolor=s.COL4,
|
||||
oac=s.fresh
|
||||
)
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Fetches, pings, and sorts public servers.',
|
||||
color=s.COL3,
|
||||
scale=0.8,
|
||||
position=(15,330),
|
||||
maxwidth=320
|
||||
)
|
||||
# separator
|
||||
iw(
|
||||
parent=s.p,
|
||||
size=(429,1),
|
||||
position=(17,330),
|
||||
texture=gt('white'),
|
||||
color=s.COL2
|
||||
)
|
||||
# cycle
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Cycle Servers',
|
||||
color=s.COL4,
|
||||
position=(19,294)
|
||||
)
|
||||
bw(
|
||||
parent=s.p,
|
||||
position=(360,278),
|
||||
size=(80,39),
|
||||
label='Cycle',
|
||||
color=s.COL2,
|
||||
textcolor=s.COL4,
|
||||
oac=s.find
|
||||
)
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Cycles through best servers and saves their players.',
|
||||
color=s.COL3,
|
||||
scale=0.8,
|
||||
position=(15,265),
|
||||
maxwidth=320,
|
||||
v_align='center'
|
||||
)
|
||||
# separator
|
||||
iw(
|
||||
parent=s.p,
|
||||
size=(429,1),
|
||||
position=(17,265),
|
||||
texture=gt('white'),
|
||||
color=s.COL2
|
||||
)
|
||||
# top
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Server Cycle Limit',
|
||||
color=s.COL4,
|
||||
position=(19,230)
|
||||
)
|
||||
s.top = tw(
|
||||
parent=s.p,
|
||||
position=(398,228),
|
||||
size=(80,50),
|
||||
text=str(c.TOP),
|
||||
color=s.COL4,
|
||||
editable=True,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
corner_scale=0.1,
|
||||
scale=10,
|
||||
allow_clear_button=False,
|
||||
shadow=0,
|
||||
flatness=1,
|
||||
)
|
||||
tw(
|
||||
parent=s.p,
|
||||
text='Maximum number of servers to cycle.',
|
||||
color=s.COL3,
|
||||
scale=0.8,
|
||||
position=(15,201),
|
||||
maxwidth=320
|
||||
)
|
||||
# separator
|
||||
iw(
|
||||
parent=s.p,
|
||||
size=(429,1),
|
||||
position=(17,200),
|
||||
texture=gt('white'),
|
||||
color=s.COL2
|
||||
)
|
||||
# players
|
||||
pl = s.plys()
|
||||
sy = max(len(pl)*30,140)
|
||||
p1 = sw(
|
||||
parent=s.p,
|
||||
position=(20,18),
|
||||
size=(205,172),
|
||||
border_opacity=0.4
|
||||
)
|
||||
p2 = ocw(
|
||||
parent=p1,
|
||||
size=(205,sy),
|
||||
background=False
|
||||
)
|
||||
0 if pl else tw(
|
||||
parent=s.p,
|
||||
position=(90,100),
|
||||
text='Cycle some servers\nto collect players',
|
||||
color=s.COL4,
|
||||
maxwidth=175,
|
||||
h_align='center'
|
||||
)
|
||||
s.kids = []
|
||||
for _,g in enumerate(pl):
|
||||
p,a = g
|
||||
s.kids.append(tw(
|
||||
parent=p2,
|
||||
size=(200,30),
|
||||
selectable=True,
|
||||
click_activate=True,
|
||||
color=s.COL3,
|
||||
text=p,
|
||||
position=(0,sy-30-30*_),
|
||||
maxwidth=175,
|
||||
on_activate_call=Call(s.hl,_,p),
|
||||
v_align='center'
|
||||
))
|
||||
# info
|
||||
iw(
|
||||
parent=s.p,
|
||||
position=(235,18),
|
||||
size=(205,172),
|
||||
texture=gt('scrollWidget'),
|
||||
mesh_transparent=gm('softEdgeOutside'),
|
||||
opacity=0.4
|
||||
)
|
||||
s.tip = tw(
|
||||
parent=s.p,
|
||||
position=(310,98),
|
||||
text='Select something to\nview server info',
|
||||
color=s.COL4,
|
||||
maxwidth=170,
|
||||
h_align='center'
|
||||
) if c.SL is None else 0
|
||||
def hl(s,_,p):
|
||||
[tw(t,color=s.COL3) for t in s.kids]
|
||||
tw(s.kids[_],color=s.COL4)
|
||||
s.info(p)
|
||||
def info(s,p):
|
||||
[_.delete() for _ in s.ikids]
|
||||
s.ikids.clear()
|
||||
s.tip and s.tip.delete()
|
||||
bst = s.__class__.BST
|
||||
for _ in bst:
|
||||
for r in _['roster']:
|
||||
if r['display_string'] == p:
|
||||
i = _
|
||||
break
|
||||
for _ in range(3):
|
||||
t = str(i['nap'[_]])
|
||||
s.ikids.append(tw(
|
||||
parent=s.p,
|
||||
position=(250,155-40*_),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=175,
|
||||
text=t,
|
||||
color=s.COL4,
|
||||
size=(175,30),
|
||||
selectable=True,
|
||||
click_activate=True,
|
||||
on_activate_call=Call(s.copy,t)
|
||||
))
|
||||
s.ikids.append(bw(
|
||||
parent=s.p,
|
||||
position=(253,30),
|
||||
size=(166,30),
|
||||
label='Connect',
|
||||
color=s.COL2,
|
||||
textcolor=s.COL4,
|
||||
oac=Call(CON,i['a'],i['p'],False)
|
||||
))
|
||||
def copy(s,t):
|
||||
s.ding(1,1)
|
||||
TIP('Copied to clipboard!')
|
||||
COPY(t)
|
||||
def plys(s):
|
||||
z = []
|
||||
me = app.plus.get_v1_account_name()
|
||||
me = [me,'\ue063'+me]
|
||||
for _ in s.__class__.BST:
|
||||
a = _['a']
|
||||
if (r:=_.get('roster',{})):
|
||||
for p in r:
|
||||
ds = p['display_string']
|
||||
0 if ds in me else z.append((ds,a))
|
||||
return sorted(z,key=lambda _: _[0].startswith('\ue030Server'))
|
||||
def snd(s,t):
|
||||
l = gs(t)
|
||||
l.play()
|
||||
teck(uf(0.14,0.18),l.stop)
|
||||
return l
|
||||
def bye(s):
|
||||
s.s1.stop()
|
||||
ocw(s.p,transition='out_scale')
|
||||
l = s.snd('laser')
|
||||
f = lambda: teck(0.01,f) if s.p else l.stop()
|
||||
f()
|
||||
def ding(s,i,j):
|
||||
a = ['Small','']
|
||||
x,y = a[i],a[j]
|
||||
s.snd('ding'+x)
|
||||
teck(0.1,gs('ding'+y).play)
|
||||
def fresh(s):
|
||||
if s.busy: BTW("Still busy!"); return
|
||||
TIP('Fetching servers...')
|
||||
s.ding(1,0)
|
||||
s.busy = True
|
||||
p = app.plus
|
||||
p.add_v1_account_transaction(
|
||||
{
|
||||
'type': 'PUBLIC_PARTY_QUERY',
|
||||
'proto': PT(),
|
||||
'lang': 'English'
|
||||
},
|
||||
callback=s.kang,
|
||||
)
|
||||
p.run_v1_account_transactions()
|
||||
def kang(s,r):
|
||||
c = s.__class__
|
||||
c.MEM = r['l']
|
||||
s.thr = []
|
||||
for _ in s.__class__.MEM:
|
||||
t = Thread(target=Call(s.ping,_))
|
||||
s.thr.append(t)
|
||||
t.start()
|
||||
teck(s.MAX*4,s.join)
|
||||
def join(s):
|
||||
c = s.__class__
|
||||
[t.join() for t in s.thr]
|
||||
far = s.MAX*3000
|
||||
c.MEM = [_ for _ in c.MEM if _['ping']]
|
||||
c.MEM.sort(key=lambda _: _['ping'])
|
||||
s.thr.clear()
|
||||
TIP(f'Loaded {len(c.MEM)} servers!')
|
||||
s.ding(0,1)
|
||||
s.busy = False
|
||||
def find(s):
|
||||
if s.busy: BTW("Still busy!"); return
|
||||
c = s.__class__
|
||||
if not c.MEM:
|
||||
BTW('Fetch some servers first!')
|
||||
return
|
||||
t = tw(query=s.top)
|
||||
if not t.isdigit():
|
||||
BTW('Invalid cycle limit!')
|
||||
return
|
||||
top = int(t)
|
||||
if not (0 < top < len(c.MEM)):
|
||||
BTW('Cycle count is too '+['big','small'][top<=0]+'!')
|
||||
return
|
||||
c.TOP = top
|
||||
s.ding(1,0)
|
||||
TIP('Starting cycle...')
|
||||
s.busy = True
|
||||
s.ci = s.lr = 0
|
||||
c.BST = c.MEM[:top]
|
||||
s.cycle()
|
||||
def cycle(s):
|
||||
_ = s.__class__.BST[s.ci]
|
||||
s.ca = _['a']
|
||||
CON(s.ca,_['p'],False)
|
||||
s.wait()
|
||||
def wait(s,i=5):
|
||||
r = GGR()
|
||||
if (r != s.lr) and r: s.__class__.BST[s.ci]['roster'] = s.lr = r; return s.next()
|
||||
if not i: s.__class__.BST[s.ci]['roster'] = []; return s.next()
|
||||
teck(0.1,Call(s.wait,i-1))
|
||||
def next(s):
|
||||
s.ci += 1
|
||||
if s.ci >= len(s.__class__.BST):
|
||||
BYE()
|
||||
teck(0.5,s.yay)
|
||||
return
|
||||
s.cycle()
|
||||
def yay(s):
|
||||
TIP('Cycle finished!')
|
||||
s.ding(0,1)
|
||||
s.busy = False
|
||||
zw('squad_button').activate()
|
||||
teck(0.3,byBordd.up)
|
||||
def ping(s,_):
|
||||
sock = ping = None
|
||||
a,p = _['a'],_['p']
|
||||
sock = socket(IPT(a),SOCK_DGRAM)
|
||||
try: sock.connect((a,p))
|
||||
except: ping = None
|
||||
else:
|
||||
st = time()
|
||||
sock.settimeout(s.MAX)
|
||||
yes = False
|
||||
for _i in range(3):
|
||||
try:
|
||||
sock.send(b'\x0b')
|
||||
r = sock.recv(10)
|
||||
except: r = None
|
||||
if r == b'\x0c':
|
||||
yes = True
|
||||
break
|
||||
sleep(s.MAX)
|
||||
ping = (time()-st)*1000 if yes else None
|
||||
finally:
|
||||
_['ping'] = ping
|
||||
sock.close()
|
||||
|
||||
# Patches
|
||||
bw = lambda *,oac=None,**k: obw(
|
||||
texture=gt('white'),
|
||||
on_activate_call=oac,
|
||||
enable_sound=False,
|
||||
**k
|
||||
)
|
||||
cw = lambda *,size=None,oac=None,**k: (p:=ocw(
|
||||
parent=zw('overlay_stack'),
|
||||
background=False,
|
||||
transition='in_scale',
|
||||
size=size,
|
||||
on_outside_click_call=oac,
|
||||
**k
|
||||
)) and (p,iw(
|
||||
parent=p,
|
||||
texture=gt('softRect'),
|
||||
size=(size[0]*1.2,size[1]*1.2),
|
||||
position=(-size[0]*0.1,-size[1]*0.1),
|
||||
opacity=0.55,
|
||||
color=(0,0,0)
|
||||
),iw(
|
||||
parent=p,
|
||||
size=size,
|
||||
texture=gt('white'),
|
||||
color=Finder.COL1
|
||||
))
|
||||
|
||||
# Global
|
||||
BTW = lambda t: (push(t,color=(1,1,0)),gs('block').play())
|
||||
TIP = lambda t: push(t,Finder.COL3)
|
||||
|
||||
# ba_meta require api 9
|
||||
# ba_meta export babase.Plugin
|
||||
class byBordd(Plugin):
|
||||
BTN = None
|
||||
@classmethod
|
||||
def up(c):
|
||||
c.BTN.activate() if c.BTN.exists() else None
|
||||
def __init__(s):
|
||||
from bauiv1lib import party
|
||||
p = party.PartyWindow
|
||||
a = '__init__'
|
||||
o = getattr(p,a)
|
||||
setattr(p,a,lambda z,*a,**k:(o(z,*a,**k),s.make(z))[0])
|
||||
def make(s,z):
|
||||
sz = (80,30)
|
||||
p = z._root_widget
|
||||
x,y = (-60,z._height-45)
|
||||
iw(
|
||||
parent=p,
|
||||
size=(sz[0]*1.34,sz[1]*1.4),
|
||||
position=(x-sz[0]*0.14,y-sz[1]*0.20),
|
||||
texture=gt('softRect'),
|
||||
opacity=0.2,
|
||||
color=(0,0,0)
|
||||
)
|
||||
s.b = s.__class__.BTN = bw(
|
||||
parent=p,
|
||||
position=(x,y),
|
||||
label='Finder',
|
||||
color=Finder.COL1,
|
||||
textcolor=Finder.COL3,
|
||||
size=sz,
|
||||
oac=lambda:Finder(s.b)
|
||||
)
|
||||
88
plugins/utilities/path.py
Executable file
88
plugins/utilities/path.py
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Bug? Feedback? Telegram >> @GalaxyA14user
|
||||
|
||||
"""
|
||||
Path v1.0 - Where it's going to be.
|
||||
|
||||
Experimental. Path tries to predict the next position of bomb.
|
||||
Path relies on velocity to operate.
|
||||
Optionally pass spaz node (holder) to assist prediction.
|
||||
Feedback is appreciated.
|
||||
"""
|
||||
|
||||
from babase import Plugin
|
||||
from bascenev1 import (
|
||||
timer as tick,
|
||||
newnode
|
||||
)
|
||||
|
||||
class Path:
|
||||
def __init__(s,node,holder=None):
|
||||
if node.body == 'crate': return
|
||||
s.node,s.kids = node,[]
|
||||
s.me = holder
|
||||
s.spy()
|
||||
def spy(s):
|
||||
n = s.node
|
||||
if not n.exists():
|
||||
[_.delete() for _ in s.kids]
|
||||
s.kids.clear()
|
||||
return
|
||||
|
||||
[_.delete() for _ in s.kids]; s.kids.clear()
|
||||
|
||||
ip = n.position
|
||||
iv = n.velocity
|
||||
if s.me and s.me.hold_node == n:
|
||||
mv = s.me.velocity
|
||||
iv = (iv[0]+mv[0],iv[1]+mv[1],iv[2]+mv[2])
|
||||
|
||||
dots = 200
|
||||
ti = 1.2
|
||||
tpd = ti / dots
|
||||
|
||||
tick(0.01, s.spy)
|
||||
for i in range(dots):
|
||||
t = i * tpd
|
||||
px = ip[0] + iv[0] * t
|
||||
py = ip[1] + iv[1] * t + 0.5 * -24 * t**2
|
||||
pz = ip[2] + iv[2] * t
|
||||
|
||||
if py <=0:
|
||||
l = newnode(
|
||||
'locator',
|
||||
owner=n,
|
||||
attrs={
|
||||
'shape': 'circleOutline',
|
||||
'size': [1],
|
||||
'color': (1,1,0),
|
||||
'draw_beauty': False,
|
||||
'additive': True,
|
||||
'position':(px,py,pz)
|
||||
}
|
||||
)
|
||||
s.kids.append(l)
|
||||
break
|
||||
dot_node = newnode(
|
||||
'text',
|
||||
owner=n,
|
||||
attrs={
|
||||
'text':'.',
|
||||
'scale':0.02,
|
||||
'position':(px, py, pz),
|
||||
'flatness':1,
|
||||
'in_world':True,
|
||||
'color':(1-i*4/dots,0,0),
|
||||
'shadow':0
|
||||
}
|
||||
)
|
||||
s.kids.append(dot_node)
|
||||
|
||||
# brobord collide grass
|
||||
# ba_meta require api 9
|
||||
# ba_meta export babase.Plugin
|
||||
class byBordd(Plugin):
|
||||
def __init__(s):
|
||||
_ = __import__('bascenev1lib').actor.bomb.Bomb
|
||||
o = _.__init__
|
||||
_.__init__ = lambda z,*a,**k: (o(z,*a,**k),Path(z.node))[0]
|
||||
475
plugins/utilities/plugtools.py
Executable file
475
plugins/utilities/plugtools.py
Executable file
|
|
@ -0,0 +1,475 @@
|
|||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Intended for personal use only
|
||||
# Bug? Feedback? Telegram >> @BroBordd
|
||||
|
||||
"""
|
||||
PlugTools v1.5 - Live Plugin Action
|
||||
|
||||
Beta. Feedback is appreciated.
|
||||
Adds a dev console tab for plugin management.
|
||||
|
||||
Features vary between:
|
||||
- Dynamic Control: Enables immediate loading and reloading of plugins.
|
||||
- Real-time Monitoring: Reports status of plugin files (new, modified, deleted).
|
||||
- Plugin Overview: Displays operational state (enabled/disabled) and integrity (original/modified).
|
||||
- Plugin Data: Provides file path, size, timestamps, and code structure analysis.
|
||||
- Navigation: Offers controls to browse the plugin list.
|
||||
- Logging: Has a built-in log display with proper indentation.
|
||||
"""
|
||||
|
||||
from os.path import (
|
||||
splitext,
|
||||
getmtime,
|
||||
getctime,
|
||||
basename,
|
||||
getsize,
|
||||
isfile,
|
||||
exists,
|
||||
join
|
||||
)
|
||||
from os import (
|
||||
scandir,
|
||||
access,
|
||||
R_OK,
|
||||
stat
|
||||
)
|
||||
from babase import (
|
||||
PluginSpec,
|
||||
Plugin,
|
||||
Call,
|
||||
env,
|
||||
app
|
||||
)
|
||||
from babase._devconsole import (
|
||||
DevConsoleTabEntry as ENT,
|
||||
DevConsoleTab as TAB
|
||||
)
|
||||
from bauiv1 import (
|
||||
get_string_width as sw,
|
||||
SpecialChar as sc,
|
||||
charstr as cs,
|
||||
apptimer as teck,
|
||||
screenmessage as push,
|
||||
getsound as gs
|
||||
)
|
||||
from traceback import format_exc as ERR
|
||||
from datetime import datetime
|
||||
from importlib import reload
|
||||
from typing import override
|
||||
from sys import modules
|
||||
from gc import collect
|
||||
from ast import (
|
||||
FunctionDef,
|
||||
ImportFrom,
|
||||
Attribute,
|
||||
ClassDef,
|
||||
Import,
|
||||
parse,
|
||||
walk,
|
||||
Name
|
||||
)
|
||||
|
||||
class PlugTools(TAB):
|
||||
KEY = 'PT_BY'
|
||||
def __init__(s):
|
||||
s.bys = META()
|
||||
s.bad = []
|
||||
s.logs = 'No errors'
|
||||
s.mem = {_:MT(_) for _ in s.bys}
|
||||
s.eye = look()
|
||||
s.e = False
|
||||
s.spy()
|
||||
def spy(s):
|
||||
b = 0
|
||||
for _ in s.bys.copy():
|
||||
if not exists(PAT(_)):
|
||||
s.bys.remove(_)
|
||||
push(f'Plugin {_} suddenly disappeared!\nAnd so, was removed from list.',color=(1,1,0))
|
||||
gs('block').play()
|
||||
s.eye = look()
|
||||
if s.hl() == _: s.hl(None)
|
||||
b = 1
|
||||
sp = app.plugins.plugin_specs.get(_,0)
|
||||
if not sp: continue
|
||||
p = app.plugins
|
||||
if getattr(sp,'enabled',False):
|
||||
o = s.sp.plugin
|
||||
if o in p.active_plugins:
|
||||
p.active_plugins.remove(o)
|
||||
if o in p.plugin_specs:
|
||||
p.plugin_specs.pop(o)
|
||||
del s.sp.plugin,o
|
||||
collect()
|
||||
try: reload(modules[NAM(_,0)])
|
||||
except: pass
|
||||
continue
|
||||
if MT(_) != s.mem[_] and _ not in s.bad:
|
||||
s.bad.append(_)
|
||||
push(f'Plugin {_} was modified!\nSee if you want to take action.',color=(1,1,0))
|
||||
gs('dingSmall').play()
|
||||
b = 1
|
||||
if hasattr(s,'sp'):
|
||||
e = getattr(s.sp,'enabled',False)
|
||||
if e != s.e:
|
||||
s.e = e
|
||||
b = 1
|
||||
eye = look()
|
||||
s1 = set(s.eye)
|
||||
s2 = set(eye)
|
||||
df = list(s2-s1)
|
||||
nu = []
|
||||
if df:
|
||||
for dd in df:
|
||||
try: _ = kang(dd)
|
||||
except:
|
||||
eye.remove(dd)
|
||||
continue
|
||||
nu.append(_)
|
||||
s.bys.append(_)
|
||||
s.mem[_] = 0
|
||||
s.bad.append(_)
|
||||
s.eye = eye
|
||||
b = 1
|
||||
if nu:
|
||||
l = len(nu)
|
||||
push(f"Found {l} new plugin{['s',''][l==1]}:\n{', '.join(nu)}\nSee what to do with {['it','them'][l!=1]}",color=(1,1,0))
|
||||
gs('dingSmallHigh').play()
|
||||
if b:
|
||||
try: s.request_refresh()
|
||||
except RuntimeError: pass
|
||||
teck(0.1,s.spy)
|
||||
@override
|
||||
def refresh(s):
|
||||
# Preload
|
||||
by = s.hl()
|
||||
if by not in s.bys:
|
||||
by = None
|
||||
s.hl(None)
|
||||
s.by = by
|
||||
s.sp = app.plugins.plugin_specs.get(by,0) if by else 0
|
||||
s.i = getattr(s,'i',0 if by is None else s.bys.index(by)//10)
|
||||
# UI
|
||||
w = s.width
|
||||
x = -w/2
|
||||
z = x+w
|
||||
# Bools
|
||||
e = s.e = getattr(s.sp,'enabled',False)
|
||||
m = by in s.bad
|
||||
d = by is None
|
||||
# Buttons
|
||||
sx = w*0.2
|
||||
mx = sx*0.98
|
||||
z -= sx
|
||||
s.button(
|
||||
'Metadata',
|
||||
pos=(z,50),
|
||||
size=(mx,43),
|
||||
call=s.metadata,
|
||||
disabled=d
|
||||
)
|
||||
s.button(
|
||||
['Load','Reload'][e],
|
||||
pos=(z,5),
|
||||
size=(mx,43),
|
||||
call=s._load,
|
||||
disabled=d
|
||||
)
|
||||
# Separator
|
||||
s.button(
|
||||
'',
|
||||
pos=(z-(w*0.006),5),
|
||||
size=(2,90)
|
||||
)
|
||||
# Plugin info
|
||||
sx = w*0.1
|
||||
z -= sx
|
||||
az = z+sx/2.23
|
||||
t = 'Entry' if d else by
|
||||
tw = GSW(t)
|
||||
mx = sx*0.9
|
||||
s.text(
|
||||
t,
|
||||
pos=(az,80),
|
||||
scale=1 if tw<mx else mx/tw,
|
||||
)
|
||||
t = 'State' if d else ['Disabled','Enabled'][e]
|
||||
tw = GSW(t)
|
||||
s.text(
|
||||
t,
|
||||
pos=(az,50),
|
||||
scale=1 if tw<mx else mx/tw,
|
||||
)
|
||||
t = 'Purity' if d else ['Original','Modified'][m]
|
||||
tw = GSW(t)
|
||||
s.text(
|
||||
t,
|
||||
pos=(az,20),
|
||||
scale=1 if tw<mx else mx/tw,
|
||||
)
|
||||
# Separator
|
||||
s.button(
|
||||
'',
|
||||
pos=(z-(w*0.0075),5),
|
||||
size=(2,90)
|
||||
)
|
||||
# Next
|
||||
sx = w*0.03
|
||||
mx = sx*0.6
|
||||
z -= sx
|
||||
s.button(
|
||||
cs(sc.RIGHT_ARROW),
|
||||
pos=(z,5),
|
||||
size=(mx,90),
|
||||
call=s.next,
|
||||
disabled=(s.i+1)*10 > len(s.bys)
|
||||
)
|
||||
# Plugins
|
||||
sx = w*0.645/5
|
||||
mx = sx*0.99
|
||||
zx = mx*0.9
|
||||
z -= sx*5
|
||||
for i in range(5):
|
||||
for j in range(2):
|
||||
k = j*5+i+s.i*10
|
||||
if k >= len(s.bys): break
|
||||
t = s.bys[k]
|
||||
tw = GSW(t)
|
||||
s.button(
|
||||
t,
|
||||
size=(mx,43),
|
||||
pos=(z+sx*i,50-45*j),
|
||||
label_scale=1 if tw<zx else zx/tw,
|
||||
call=Call(s.hl,t),
|
||||
style=[['blue','blue_bright'],['purple','purple_bright']][t in s.bad][t==by]
|
||||
)
|
||||
# Prev
|
||||
sx = w*0.03
|
||||
mx = sx*0.6
|
||||
z -= sx*0.7
|
||||
s.button(
|
||||
cs(sc.LEFT_ARROW),
|
||||
pos=(z,5),
|
||||
size=(mx,90),
|
||||
call=s.prev,
|
||||
disabled=s.i==0
|
||||
)
|
||||
if s.height <= 100: return
|
||||
# Expanded logs
|
||||
t = s.logs
|
||||
h = 25
|
||||
pos = (x+10,s.height)
|
||||
z = len(t)
|
||||
p = list(pos)
|
||||
m = max(t.replace('\\n','') or [''],key=GSW)
|
||||
l = GSW(str(m))/1.2
|
||||
ln = t.split('\\n')
|
||||
mm = max(ln,key=GSW)
|
||||
sk = 0.8
|
||||
ml = (s.height-100) * 0.04
|
||||
ww = (l*sk)*len(mm)
|
||||
sk = sk if ww<s.width else (s.width*0.98/ww)*sk
|
||||
zz = len(ln)
|
||||
sk = sk if zz<=ml else (ml/zz)*sk
|
||||
xf = 0
|
||||
for i in range(z):
|
||||
p[0] += [l*sk,0][i==0]
|
||||
if xf: xf = 0; continue
|
||||
j = t[i]
|
||||
k = t[i+1] if (i+1) < z else j
|
||||
if j == '\\' and k == 'n':
|
||||
p[0] = pos[0]-(l*1.5)*sk
|
||||
p[1] -= h*(sk*1.28)
|
||||
xf = 1
|
||||
continue
|
||||
s.text(
|
||||
j,
|
||||
pos=tuple(p),
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
scale=sk
|
||||
)
|
||||
def hl(s,i=None):
|
||||
i and deek()
|
||||
c = app.config
|
||||
if i is None: return c.get(s.KEY,None)
|
||||
c[s.KEY] = i
|
||||
c.commit()
|
||||
s.request_refresh()
|
||||
def _load(s):
|
||||
h = ['load','reload'][s.e]
|
||||
ex,er = s.load()
|
||||
if ex:
|
||||
k = f': {ex}' if str(ex).strip() else ''
|
||||
j = f'Error {h}ing {s.by}'
|
||||
push(f'{j}{k}\nExpand dev console to see more.\nTraceback dumped to terminal too.',color=(1,0,0))
|
||||
gs('error').play()
|
||||
m = j+':\n'+er
|
||||
print('[PlugTools] '+m)
|
||||
s.logs = m.replace('\n','\\n')
|
||||
s.request_refresh()
|
||||
return
|
||||
s.logs = 'No errors'
|
||||
if ex is False: return
|
||||
push(h.title()+'ed '+s.by,color=(0,1,0))
|
||||
gs('gunCocking').play()
|
||||
s.request_refresh()
|
||||
def load(s):
|
||||
_ = s.by
|
||||
if _ in s.bad:
|
||||
s.bad.remove(_)
|
||||
s.mem[_] = MT(_)
|
||||
p = app.plugins
|
||||
if s.e:
|
||||
if hasattr(s.sp,'plugin'):
|
||||
o = s.sp.plugin
|
||||
if o in p.active_plugins:
|
||||
p.active_plugins.remove(o)
|
||||
del s.sp.plugin
|
||||
collect()
|
||||
try: m = reload(modules[NAM(_,0)])
|
||||
except KeyError:
|
||||
gs('block').play()
|
||||
push(f"{s.by} is malformed!\nAre you sure there's no errors?",color=(1,1,0))
|
||||
return (False,0)
|
||||
except Exception as ex: return (ex,ERR())
|
||||
else: m = __import__(NAM(_,0))
|
||||
try: cls = getattr(m,_.split('.',1)[1])
|
||||
except Exception as ex: return (ex,ERR())
|
||||
try: ins = cls()
|
||||
except Exception as ex: return (ex,ERR())
|
||||
try: ins.on_app_running()
|
||||
except Exception as ex: return (ex,ERR())
|
||||
s.sp = PluginSpec(class_path=_,loadable=True)
|
||||
s.sp.enabled = True
|
||||
s.sp.plugin = ins
|
||||
p.plugin_specs[_] = s.sp
|
||||
p.active_plugins.append(ins)
|
||||
return (0,0)
|
||||
def metadata(s):
|
||||
f = PAT(s.sp.class_path)
|
||||
info = []
|
||||
if exists(f):
|
||||
info.append(f'File Path: {f}')
|
||||
info.append("File Exists: Yes")
|
||||
info.append(f"File Size: {getsize(f)} bytes")
|
||||
try:
|
||||
with open(f, 'r', encoding='utf-8', errors='ignore') as file:
|
||||
lines = file.readlines()
|
||||
content = "".join(lines) # Read entire content for AST parsing and char count
|
||||
line_count = len(lines)
|
||||
char_count = len(content)
|
||||
|
||||
info.append(f"Line Count: {line_count}")
|
||||
info.append(f"Character Count: {char_count}")
|
||||
|
||||
# Python specific programmatic analysis
|
||||
function_count = 0
|
||||
class_count = 0
|
||||
import_statement_count = 0
|
||||
comment_lines = 0
|
||||
blank_lines = 0
|
||||
|
||||
try:
|
||||
tree = parse(content) # Use parse directly
|
||||
for node in walk(tree): # Use walk directly
|
||||
if isinstance(node, FunctionDef): # Use FunctionDef directly
|
||||
function_count += 1
|
||||
elif isinstance(node, ClassDef): # Use ClassDef directly
|
||||
class_count += 1
|
||||
elif isinstance(node, (Import, ImportFrom)): # Use Import, ImportFrom directly
|
||||
import_statement_count += 1
|
||||
# Iterate through physical lines for comments and blank lines
|
||||
for line in lines:
|
||||
stripped_line = line.strip()
|
||||
if not stripped_line:
|
||||
blank_lines += 1
|
||||
elif stripped_line.startswith('#'):
|
||||
comment_lines += 1
|
||||
info.append(f"Function Definitions: {function_count}")
|
||||
info.append(f"Class Definitions: {class_count}")
|
||||
info.append(f"Import Statements: {import_statement_count}")
|
||||
info.append(f"Comment Lines: {comment_lines}")
|
||||
info.append(f"Blank Lines: {blank_lines}")
|
||||
|
||||
except SyntaxError as se:
|
||||
info.append(f"Python Syntax Error: {se}")
|
||||
except Exception as ast_e:
|
||||
info.append(f"Error analyzing Python file structure: {ast_e}")
|
||||
|
||||
except Exception as e:
|
||||
info.append(f"Could not read file content for analysis: {e}")
|
||||
|
||||
creation_time = datetime.fromtimestamp(getctime(f))
|
||||
info.append(f"Creation Time: {creation_time}")
|
||||
|
||||
mod_time = datetime.fromtimestamp(getmtime(f))
|
||||
info.append(f"Last Modified: {mod_time}")
|
||||
else:
|
||||
info.append(f'File Path: {f}')
|
||||
info.append("File Exists: No")
|
||||
push('\n'.join(info))
|
||||
gs('powerup01').play()
|
||||
def next(s):
|
||||
deek()
|
||||
s.i += 1
|
||||
s.request_refresh()
|
||||
def prev(s):
|
||||
deek()
|
||||
s.i -= 1
|
||||
s.request_refresh()
|
||||
|
||||
MT = lambda _: stat(PAT(_))
|
||||
GSW = lambda s: sw(s,suppress_warning=True)
|
||||
NAM = lambda _,py=1: _.split('.',1)[0]+['','.py'][py]
|
||||
PAT = lambda _: join(ROOT,NAM(_))
|
||||
ROOT = env()['python_directory_user']
|
||||
META = lambda: app.meta.scanresults.exports_by_name('babase.Plugin')
|
||||
def look():
|
||||
python_files = []
|
||||
try:
|
||||
with scandir(ROOT) as entries:
|
||||
for entry in entries:
|
||||
if entry.is_file() and entry.name.endswith(".py"):
|
||||
if access(entry.path, R_OK):
|
||||
python_files.append(entry.path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except PermissionError:
|
||||
pass
|
||||
return python_files
|
||||
def kang(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
source_code = f.read()
|
||||
|
||||
tree = parse(source_code)
|
||||
lines = source_code.splitlines()
|
||||
export_line_num = -1
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip() == '# ba_meta export babase.Plugin':
|
||||
export_line_num = i + 1
|
||||
break
|
||||
if export_line_num == -1:
|
||||
return None
|
||||
|
||||
filename_without_ext = splitext(basename(file_path))[0]
|
||||
for node in tree.body:
|
||||
if isinstance(node, ClassDef):
|
||||
if node.lineno > export_line_num:
|
||||
for base in node.bases:
|
||||
if (isinstance(base, Name) and base.id == 'Plugin') or \
|
||||
(isinstance(base, Attribute) and base.attr == 'Plugin' and isinstance(base.value, Name) and base.value.id == 'babase'):
|
||||
return f"{filename_without_ext}.{node.name}"
|
||||
return None
|
||||
deek = lambda: gs('deek').play()
|
||||
|
||||
# brobord collide grass
|
||||
# ba_meta require api 9
|
||||
# ba_meta export babase.Plugin
|
||||
class byBordd(Plugin):
|
||||
def __init__(s):
|
||||
C = PlugTools
|
||||
N = C.__name__
|
||||
E = ENT(N,C)
|
||||
I = app.devconsole
|
||||
I.tabs = [_ for _ in I.tabs if _.name != N]+[E]
|
||||
I._tab_instances[N] = E.factory()
|
||||
793
plugins/utilities/power.py
Executable file
793
plugins/utilities/power.py
Executable file
|
|
@ -0,0 +1,793 @@
|
|||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Intended for personal use only
|
||||
# Bug? Feedback? Telegram >> @GalaxyA14user
|
||||
|
||||
"""
|
||||
Power v2.7 - With one click
|
||||
|
||||
Experimental. Feedback is appreciated.
|
||||
Adds a dev console tab with some features I find useful.
|
||||
Power is mainly focused on the multiplayer side.
|
||||
Can be considered a good tool to have around.
|
||||
"""
|
||||
|
||||
from datetime import datetime as DT
|
||||
from typing import override
|
||||
from babase import (
|
||||
clipboard_is_supported as CIS,
|
||||
clipboard_set_text as CST,
|
||||
Plugin,
|
||||
app
|
||||
)
|
||||
from babase._devconsole import (
|
||||
DevConsoleTabEntry as ENT,
|
||||
DevConsoleTab as TAB
|
||||
)
|
||||
from bascenev1 import (
|
||||
get_connection_to_host_info_2 as HOST,
|
||||
disconnect_from_host as LEAVE,
|
||||
disconnect_client as DISC,
|
||||
broadcastmessage as push,
|
||||
get_chat_messages as GCM,
|
||||
connect_to_party as CON,
|
||||
get_game_roster as ROST,
|
||||
chatmessage as chat
|
||||
)
|
||||
from bauiv1 import (
|
||||
get_string_width as sw,
|
||||
SpecialChar as sc,
|
||||
apptimer as teck,
|
||||
charstr as cs,
|
||||
Call
|
||||
)
|
||||
|
||||
class Power(TAB):
|
||||
def __init__(s):
|
||||
s.j = [None,None,None]; s.ji = 1
|
||||
[setattr(s,_,None) for _ in 'cpnh']
|
||||
[setattr(s,_,{}) for _ in ['rr','hi']]
|
||||
[setattr(s,_,[]) for _ in ['cm','og','r','ls']]
|
||||
[setattr(s,_,0) for _ in ['ii','eii','ci','re','ri','eri','li','lii']]
|
||||
teck(3,s.spy)
|
||||
def rf(s):
|
||||
try: s.request_refresh()
|
||||
except RuntimeError: pass
|
||||
def spy(s):
|
||||
_ = 0
|
||||
r = ROST()
|
||||
if r != s.r:
|
||||
s.rr = {i['display_string']:(i['client_id'],i['players']) for i in r}
|
||||
s.r = r
|
||||
_ = 1
|
||||
h = HOST()
|
||||
if h != s.h:
|
||||
s.ri = 0
|
||||
s.h = h
|
||||
_ = 1
|
||||
t = getattr(s.h, 'name', 'Not in a server')
|
||||
a = getattr(s.h, 'address', '127.0.0.1')
|
||||
p = getattr(s.h, 'port', '43210')
|
||||
if s.h:
|
||||
tt = t if t.strip() else '...'
|
||||
if t.strip() or not any(key[1] == a for key in s.hi):
|
||||
s.hi[(tt, a)] = (tt, p)
|
||||
if tt != '...':
|
||||
if ('...', a) in s.hi:
|
||||
del s.hi[('...', a)]
|
||||
ng = GCM()
|
||||
if s.og != ng:
|
||||
s.og = ng
|
||||
ls = ng[-1]
|
||||
ch = s.cm[0][1] if len(s.cm) else 0
|
||||
if ch and ls == s.cm[0][0]: s.cm[0] = (ls,ch+1)
|
||||
else: s.cm.insert(0,(ls,1))
|
||||
if s.ci: s.ci += 1
|
||||
_ = 1
|
||||
_ and s.rf()
|
||||
teck(0.1,s.spy)
|
||||
@override
|
||||
def refresh(s):
|
||||
sf = s.width / 1605.3
|
||||
zf = s.height / 648
|
||||
x = -s.width/2
|
||||
T,B = s.text,s.button
|
||||
if len(s.r) and s.ri >= len(s.r): s.ri = len(s.r) - 1
|
||||
if len(s.r) and s.eri >= len(s.r): s.eri = len(s.r) - 1
|
||||
if s.j[0] == 'JRejoin' and s.ji <= s.re:
|
||||
s.ji = s.re + 1
|
||||
push('Job time cannot be less than rejoin time\nwhen job is JRejoin. Updated job time to '+str(s.ji),color=(1,1,0))
|
||||
if s.height > 100:
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x + 10 * sf, 606*zf),
|
||||
size=(280*sf,35*zf),
|
||||
disabled=s.eri <= 0,
|
||||
call=Call(s.mv,'eri',-1)
|
||||
)
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x + 10 * sf, 290*zf),
|
||||
size=(280*sf,35*zf),
|
||||
disabled=s.eri >= len(s.r)-7,
|
||||
call=Call(s.mv,'eri',1)
|
||||
)
|
||||
nt = "No roster detected\nJoin some public party"
|
||||
w = GSW(nt)
|
||||
0 if len(s.r) else T(
|
||||
nt,
|
||||
pos=(x + 150 * sf, 495*zf),
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
scale=1 if w<(290*sf) else (290*sf)/w
|
||||
)
|
||||
for i,z in enumerate(s.rr.items()):
|
||||
if i < s.eri: continue
|
||||
if i>=(s.eri+7): break
|
||||
n,g = z
|
||||
c,p = g
|
||||
w = GSW(n)
|
||||
B(
|
||||
n,
|
||||
size=(280 * sf, 37*zf),
|
||||
pos=(x + 10 * sf, (564-39*(i-s.eri))*zf),
|
||||
style=[['blue','blue_bright'],['purple','purple_bright']][not p][s.c==c],
|
||||
call=Call(s.prv,c,p,n),
|
||||
label_scale=1 if w < 280 * sf else (280 * sf)/w
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(280 * sf, 2),
|
||||
pos=(x + 10 * sf, 280*zf),
|
||||
style='bright'
|
||||
)
|
||||
bb = s.c is None
|
||||
B(
|
||||
'Bomb' if bb else (['Client','Host'][s.c==-1]+f' {s.c}'),
|
||||
pos=(x + 10 * sf, 230*zf),
|
||||
size=(280 * sf, 40*zf),
|
||||
disabled=bb,
|
||||
call=Call(push,str(s.n))
|
||||
)
|
||||
B(
|
||||
'Mention',
|
||||
size=(280 * sf, 40*zf),
|
||||
pos=(x + 10 * sf, 185*zf),
|
||||
call=Call(chat,str(s.n)),
|
||||
disabled=bb
|
||||
)
|
||||
B(
|
||||
'Players',
|
||||
size=(280 * sf, 40*zf),
|
||||
pos=(x + 10 * sf, 140*zf),
|
||||
call=Call(push,'\n'.join([' '.join([f'{i}={j}' for i,j in _.items()]) for _ in s.p]) if s.p else ''),
|
||||
disabled=bb or (not s.p)
|
||||
)
|
||||
B(
|
||||
'Kick',
|
||||
size=(280 * sf, 40*zf),
|
||||
pos=(x + 10 * sf, 95*zf),
|
||||
call=Call(KICK,lambda:s.rr[s.n][0]),
|
||||
disabled=bb or (s.c==-1)
|
||||
)
|
||||
B(
|
||||
'JKick',
|
||||
size=(280 * sf, 40*zf),
|
||||
pos=(x + 10 * sf, 50*zf),
|
||||
call=Call(s.job,Call(KICK,lambda:s.rr[s.n][0]),['JKick',s.c,s.n]),
|
||||
disabled=bb or (s.c==-1)
|
||||
)
|
||||
B(
|
||||
'Vote',
|
||||
size=(280 * sf, 40*zf),
|
||||
pos=(x + 10 * sf, 5*zf),
|
||||
call=Call(chat,'1'),
|
||||
disabled=not s.r
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, 635*zf),
|
||||
pos=(x + 300 * sf, 5*zf),
|
||||
style='bright'
|
||||
)
|
||||
t = getattr(s.h,'name','Not in a server')
|
||||
a = getattr(s.h,'address','127.0.0.1')
|
||||
p = getattr(s.h,'port','43210')
|
||||
w = GSW(t)
|
||||
B(
|
||||
t if t.strip() else 'Loading...',
|
||||
size=(400 * sf, 35*zf),
|
||||
pos=(x + 311 * sf, 606*zf),
|
||||
disabled=not s.h,
|
||||
label_scale=1 if w < 390 * sf else (390 * sf)/w,
|
||||
call=Call(push,f"{t}\nHosted on build {getattr(s.h,'build_number','0')}" if t.strip() else 'Server is still loading...\nIf it remains stuck on this\nthen either party is full, or a network issue.'),
|
||||
)
|
||||
w = GSW(a)
|
||||
B(
|
||||
a,
|
||||
size=(300 * sf, 35*zf),
|
||||
pos=(x + 311 * sf, 568*zf),
|
||||
call=Call(COPY,a),
|
||||
disabled=not s.h,
|
||||
label_scale=1 if w < 290 * sf else (290 * sf)/w
|
||||
)
|
||||
w = GSW(str(p))
|
||||
B(
|
||||
str(p),
|
||||
size=(97 * sf, 35*zf),
|
||||
pos=(x + 614 * sf, 568*zf),
|
||||
disabled=not s.h,
|
||||
call=Call(COPY,str(p)),
|
||||
label_scale=1 if w < 90 * sf else (90 * sf)/w
|
||||
)
|
||||
B(
|
||||
'Leave',
|
||||
size=(400 * sf, 35*zf),
|
||||
pos=(x + 311 * sf, 530*zf),
|
||||
call=LEAVE,
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'Rejoin',
|
||||
size=(200 * sf, 35*zf),
|
||||
pos=(x + 311 * sf, 492*zf),
|
||||
call=Call(REJOIN,a,p,lambda:s.re),
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'JRejoin',
|
||||
size=(197 * sf, 35*zf),
|
||||
pos=(x + 514 * sf, 492*zf),
|
||||
call=Call(s.job,Call(REJOIN,a,p,lambda:s.re),['JRejoin',a,str(p)]),
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'+',
|
||||
size=(131 * sf, 35*zf),
|
||||
pos=(x + 579 * sf, 454*zf),
|
||||
call=Call(s.mv,'re',1)
|
||||
)
|
||||
B(
|
||||
str(s.re or 0.1),
|
||||
size=(131 * sf, 35*zf),
|
||||
pos=(x + 444 * sf, 454*zf),
|
||||
call=Call(push,f"Rejoins after {s.re or 0.1} second{['','s'][s.re!=1]}\nKeep this 0.1 unless server kicks fast rejoins\nLife in server = job time - rejoin time")
|
||||
)
|
||||
B(
|
||||
'-',
|
||||
size=(131 * sf, 35*zf),
|
||||
pos=(x + 311 * sf, 454*zf),
|
||||
disabled=s.re<=0.5,
|
||||
call=Call(s.mv,'re',-1)
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, 635*zf),
|
||||
pos=(x + 720 * sf, 5*zf),
|
||||
style='bright'
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(400 * sf, 2),
|
||||
pos=(x + 311 * sf, 445*zf),
|
||||
style='bright'
|
||||
)
|
||||
for i,e in enumerate(s.hi.items()):
|
||||
if i < s.eii: continue
|
||||
if i >= (s.eii+9): break
|
||||
g,v = e
|
||||
_,a = g
|
||||
n,p = v
|
||||
w = GSW(n)
|
||||
B(
|
||||
n,
|
||||
size=(400 * sf, 37*zf),
|
||||
pos=(x + 311 * sf, (358-39*(i-s.eii))*zf),
|
||||
label_scale=1 if w < 290 * sf else (290 * sf)/w,
|
||||
call=Call(JOIN,a,p,False),
|
||||
disabled=n == '...'
|
||||
)
|
||||
nt = "Server join history\nServers you join are saved here"
|
||||
w = GSW(nt)
|
||||
0 if len(s.hi) else T(
|
||||
nt,
|
||||
pos=(x + 510 * sf, 265*zf),
|
||||
v_align='top',
|
||||
scale=1 if w<(380*sf) else (380*sf)/w
|
||||
)
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x + 311 * sf, 8*zf),
|
||||
size=(398*sf, 35*zf),
|
||||
disabled=s.eii >= len(s.hi)-9,
|
||||
call=Call(s.mv,'eii',1)
|
||||
)
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x + 311 * sf, 400*zf),
|
||||
size=(400*sf, 35*zf),
|
||||
disabled=s.eii <= 0,
|
||||
call=Call(s.mv,'eii',-1)
|
||||
)
|
||||
bb = s.j[0] is None
|
||||
B(
|
||||
'No job' if bb else 'Job',
|
||||
size=(300 * sf, 35*zf),
|
||||
pos=(x + 727 * sf, 606*zf),
|
||||
call=Call(push,s.j[0]),
|
||||
disabled=bb
|
||||
)
|
||||
w = 0 if bb else GSW(str(s.j[1]))
|
||||
B(
|
||||
'Target' if bb else str(s.j[1]),
|
||||
size=(300 * sf, 35*zf),
|
||||
pos=(x + 727 * sf, 568*zf),
|
||||
call=Call(push,s.j[2]),
|
||||
disabled=bb,
|
||||
label_scale=1 if w<110 * sf else (110 * sf)/w
|
||||
)
|
||||
B(
|
||||
'Stop',
|
||||
size=(300 * sf, 35*zf),
|
||||
pos=(x + 727 * sf, 530*zf),
|
||||
call=Call(s.job,None,[None,None,None]),
|
||||
disabled=bb
|
||||
)
|
||||
B(
|
||||
'+',
|
||||
size=(96 * sf, 35*zf),
|
||||
pos=(x + 931 * sf, 492*zf),
|
||||
call=Call(s.mv,'ji',1)
|
||||
)
|
||||
B(
|
||||
str(s.ji or 0.1),
|
||||
size=(100 * sf, 35*zf),
|
||||
pos=(x + 828 * sf, 492*zf),
|
||||
call=Call(push,f"Job runs every {s.ji or 0.1} second{['','s'][s.ji!=1]}")
|
||||
)
|
||||
B(
|
||||
'-',
|
||||
size=(98 * sf, 35*zf),
|
||||
pos=(x + 727 * sf, 492*zf),
|
||||
disabled=s.ji<=0.5,
|
||||
call=Call(s.mv,'ji',-1)
|
||||
)
|
||||
B(
|
||||
'Power',
|
||||
size=(300 * sf, 35*zf),
|
||||
pos=(x + 727 * sf, 454*zf),
|
||||
call=Call(push,'Power v2.5 FullUI\nCollapse dev console to switch to MinUI')
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(300 * sf, 2),
|
||||
pos=(x + 727 * sf, 445*zf),
|
||||
style='bright'
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, 635*zf),
|
||||
pos=(x + 1034 * sf, 5*zf),
|
||||
style='bright'
|
||||
)
|
||||
0 if len(s.cm) else T(
|
||||
'Chat is still empty.\nHurry up and fill it with nonesense',
|
||||
pos=(x+1320 * sf, 330 * zf)
|
||||
)
|
||||
for i,g in enumerate(s.cm):
|
||||
if i < s.ci: continue
|
||||
if i >= s.ci+15: break
|
||||
i = i - s.ci
|
||||
m,_ = g
|
||||
sn,ms = m.split(': ',1)
|
||||
w = GSW(sn)
|
||||
w = [w,30*sf][w<30*sf]
|
||||
s1 = [w,200*sf][w>200*sf]
|
||||
B(
|
||||
sn,
|
||||
size=(s1,35*zf),
|
||||
pos=(x + 1040*sf, (48+37*i)*zf),
|
||||
style='purple',
|
||||
label_scale=1 if w<(s1-10*sf) else (s1-10*sf)/w,
|
||||
call=Call(s.chk,sn)
|
||||
)
|
||||
s2 = 555*sf - s1 - 53*(_>1)
|
||||
B(
|
||||
'',
|
||||
size=(s2,35*zf),
|
||||
pos=(x + 1045*sf+s1, (48+37*i)*zf),
|
||||
style='black'
|
||||
)
|
||||
w = GSW(ms)
|
||||
T(
|
||||
ms,
|
||||
pos=(x + s1+(1050)*sf, (48+17+37*i)*zf),
|
||||
scale=1 if w<(s2-10*sf) else (s2-10*sf)/w,
|
||||
h_align='left'
|
||||
)
|
||||
z = f'x{_}'
|
||||
w = GSW(z)
|
||||
_>1 and B(
|
||||
z,
|
||||
pos=(x+s1+s2+(1050)*sf,(48+37*i)*zf),
|
||||
size=(50*sf,35*zf),
|
||||
label_scale=1 if w<(40*sf) else (40*sf)/w,
|
||||
style='yellow_bright'
|
||||
)
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x+1042*sf,8*zf),
|
||||
size=(555*sf,35*zf),
|
||||
call=Call(s.mv,'ci',-1),
|
||||
disabled=s.ci <= 0 or not s.cm
|
||||
)
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x+1042*sf,606*zf),
|
||||
size=(555*sf,35*zf),
|
||||
call=Call(s.mv,'ci',1),
|
||||
disabled=(s.ci >= len(s.cm)-15) or not s.cm
|
||||
)
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x+727*sf,8*zf),
|
||||
size=(300*sf,35*zf),
|
||||
disabled=(s.li >= len(s.ls)-16) or not s.ls,
|
||||
call=Call(s.mv,'li',1)
|
||||
)
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x+727*sf,400*zf),
|
||||
size=(300*sf,35*zf),
|
||||
disabled=s.li<=0,
|
||||
call=Call(s.mv,'li',-1)
|
||||
)
|
||||
0 if s.ls else T(
|
||||
'Job logs here\nLike you even care',
|
||||
pos=(x+875*sf,232*zf)
|
||||
)
|
||||
for _,g in enumerate(s.ls):
|
||||
if _ < s.li: continue
|
||||
if _ >= s.li+16: break
|
||||
_ = _ - s.li
|
||||
l,t = g
|
||||
B(
|
||||
'',
|
||||
pos=(x+727*sf,(376-_*22)*zf),
|
||||
size=(300*sf,20*zf),
|
||||
label_scale=0.7,
|
||||
corner_radius=0,
|
||||
style='black',
|
||||
call=Call(push,t)
|
||||
)
|
||||
T(
|
||||
l,
|
||||
pos=(x+732*sf,(386-_*22)*zf),
|
||||
scale=0.6,
|
||||
h_align='left'
|
||||
)
|
||||
else:
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x + 10 * sf, 10),
|
||||
size=(30 * sf, s.height-17),
|
||||
disabled=(s.ri >= len(s.r)-3) or not s.r,
|
||||
call=Call(s.mv,'ri',1)
|
||||
)
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x + 250 * sf, 10),
|
||||
size=(30 * sf, s.height-17),
|
||||
disabled=(s.ri <= 0) or not s.r,
|
||||
call=Call(s.mv,'ri',-1)
|
||||
)
|
||||
nt = "No roster\nYou're alone"
|
||||
w = GSW(nt)
|
||||
0 if len(s.r) else T(
|
||||
nt,
|
||||
pos=(x + 147 * sf, s.height-17),
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
scale=1 if w<(200*sf) else (200*sf)/w
|
||||
)
|
||||
for i,z in enumerate(s.rr.items()):
|
||||
if i < s.ri: continue
|
||||
if i>=(s.ri+3): break
|
||||
n,g = z
|
||||
c,p = g
|
||||
w = GSW(n)
|
||||
B(
|
||||
n,
|
||||
size=(210 * sf, 27),
|
||||
pos=(x + 40 * sf, s.height-35-27*(i-s.ri)),
|
||||
style=[['blue','blue_bright'],['purple','purple_bright']][not p][s.c==c],
|
||||
call=Call(s.prv,c,p,n),
|
||||
label_scale=1 if w < 200 * sf else (200 * sf)/w
|
||||
)
|
||||
bb = s.c is None
|
||||
B(
|
||||
'Bomb' if bb else (['Client','Host'][s.c==-1]+f' {s.c}'),
|
||||
pos=(x + 287 * sf, s.height-34),
|
||||
size=(120 * sf, 27),
|
||||
disabled=bb,
|
||||
call=Call(push,str(s.n))
|
||||
)
|
||||
B(
|
||||
'Mention',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 287 * sf, s.height-90),
|
||||
call=Call(chat,str(s.n)),
|
||||
disabled=bb
|
||||
)
|
||||
B(
|
||||
'Players',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 287 * sf, s.height-62),
|
||||
call=Call(push,'\n'.join([' '.join([f'{i}={j}' for i,j in _.items()]) for _ in s.p]) if s.p else ''),
|
||||
disabled=bb or (not s.p)
|
||||
)
|
||||
B(
|
||||
'Kick',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 407 * sf, s.height-34),
|
||||
call=Call(KICK,lambda:s.rr[s.n][0]),
|
||||
disabled=bb or (s.c==-1)
|
||||
)
|
||||
B(
|
||||
'JKick',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 407 * sf, s.height-62),
|
||||
call=Call(s.job,Call(KICK,lambda:s.rr[s.n][0]),['JKick',s.c,s.n]),
|
||||
disabled=bb or (s.c==-1)
|
||||
)
|
||||
B(
|
||||
'Vote',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 407 * sf, s.height-90),
|
||||
call=Call(chat,'1'),
|
||||
disabled=not s.r
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, s.height-17),
|
||||
pos=(x + 535 * sf, 10),
|
||||
style='bright'
|
||||
)
|
||||
bb = s.j[0] is None
|
||||
B(
|
||||
'No job' if bb else 'Job',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 544 * sf, s.height-34),
|
||||
call=Call(push,s.j[0]),
|
||||
disabled=bb
|
||||
)
|
||||
w = 0 if bb else GSW(str(s.j[1]))
|
||||
B(
|
||||
'Target' if bb else str(s.j[1]),
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 544 * sf, s.height-62),
|
||||
call=Call(push,s.j[2]),
|
||||
disabled=bb,
|
||||
label_scale=1 if w<110 * sf else (110 * sf)/w
|
||||
)
|
||||
B(
|
||||
'Stop',
|
||||
size=(120 * sf, 27),
|
||||
pos=(x + 544 * sf, s.height-90),
|
||||
call=Call(s.job,None,[None,None,None]),
|
||||
disabled=bb
|
||||
)
|
||||
B(
|
||||
'+',
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 664 * sf, s.height-34),
|
||||
call=Call(s.mv,'ji',1)
|
||||
)
|
||||
B(
|
||||
str(s.ji or 0.1),
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 664 * sf, s.height-62),
|
||||
call=Call(push,f"Job runs every {s.ji or 0.1} second{['','s'][s.ji!=1]}")
|
||||
)
|
||||
B(
|
||||
'-',
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 664 * sf, s.height-90),
|
||||
disabled=s.ji<=0.5,
|
||||
call=Call(s.mv,'ji',-1)
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, s.height-17),
|
||||
pos=(x + 722 * sf, 10),
|
||||
style='bright'
|
||||
)
|
||||
t = getattr(s.h,'name','Not in a server')
|
||||
a = getattr(s.h,'address','127.0.0.1')
|
||||
p = getattr(s.h,'port','43210')
|
||||
w = GSW(t)
|
||||
B(
|
||||
t if t.strip() else 'Loading...',
|
||||
size=(300 * sf, 27),
|
||||
pos=(x + 732 * sf, s.height-34),
|
||||
disabled=not s.h,
|
||||
label_scale=1 if w < 290 * sf else (290 * sf)/w,
|
||||
call=Call(push,f"{t}\nHosted on build {getattr(s.h,'build_number','0')}" if t.strip() else 'Server is still loading...\nIf it remains stuck on this\nthen either party is full, or a network issue.'),
|
||||
)
|
||||
w = GSW(a)
|
||||
B(
|
||||
a,
|
||||
size=(200 * sf, 27),
|
||||
pos=(x + 732 * sf, s.height-62),
|
||||
call=Call(COPY,a),
|
||||
disabled=not s.h,
|
||||
label_scale=1 if w < 190 * sf else (190 * sf)/w
|
||||
)
|
||||
w = GSW(str(p))
|
||||
B(
|
||||
str(p),
|
||||
size=(97 * sf, 27),
|
||||
pos=(x + 935 * sf, s.height-62),
|
||||
disabled=not s.h,
|
||||
call=Call(COPY,str(p)),
|
||||
label_scale=1 if w < 90 * sf else (90 * sf)/w
|
||||
)
|
||||
B(
|
||||
'Leave',
|
||||
size=(100 * sf, 27),
|
||||
pos=(x + 732 * sf, s.height-90),
|
||||
call=LEAVE,
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'Rejoin',
|
||||
size=(97 * sf, 27),
|
||||
pos=(x + 835 * sf, s.height-90),
|
||||
call=Call(REJOIN,a,p,lambda:s.re),
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'JRejoin',
|
||||
size=(97 * sf, 27),
|
||||
pos=(x + 935 * sf, s.height-90),
|
||||
call=Call(s.job,Call(REJOIN,a,p,lambda:s.re),['JRejoin',a,str(p)]),
|
||||
disabled=not s.h
|
||||
)
|
||||
B(
|
||||
'+',
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 1035 * sf, s.height-34),
|
||||
call=Call(s.mv,'re',1)
|
||||
)
|
||||
B(
|
||||
str(s.re or 0.1),
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 1035 * sf, s.height-62),
|
||||
call=Call(push,f"Rejoins after {s.re or 0.1} second{['','s'][s.re!=1]}\nKeep this 0.1 unless server kicks fast rejoins\nLife in server = job time - rejoin time")
|
||||
)
|
||||
B(
|
||||
'-',
|
||||
size=(50 * sf, 27),
|
||||
pos=(x + 1035 * sf, s.height-90),
|
||||
disabled=s.re<=0.5,
|
||||
call=Call(s.mv,'re',-1)
|
||||
)
|
||||
B(
|
||||
'',
|
||||
size=(2, s.height-17),
|
||||
pos=(x + 1092 * sf, 10),
|
||||
style='bright'
|
||||
)
|
||||
for i,e in enumerate(s.hi.items()):
|
||||
if i < s.ii: continue
|
||||
if i >= (s.ii+3): break
|
||||
g,v = e
|
||||
_,a = g
|
||||
n,p = v
|
||||
w = GSW(n)
|
||||
B(
|
||||
n,
|
||||
size=(300 * sf, 27),
|
||||
pos=(x + 1134 * sf, s.height-34-28*(i-s.ii)),
|
||||
label_scale=1 if w < 290 * sf else (290 * sf)/w,
|
||||
call=Call(JOIN,a,p,False),
|
||||
disabled=n == '...'
|
||||
)
|
||||
nt = "Your server join history\nwill appear here. Hi."
|
||||
w = GSW(nt)
|
||||
0 if len(s.hi) else T(
|
||||
nt,
|
||||
pos=(x + 1285 * sf, s.height-17),
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
scale=1 if w<(280*sf) else (280*sf)/w
|
||||
)
|
||||
B(
|
||||
cs(sc.DOWN_ARROW),
|
||||
pos=(x + 1102 * sf, 10),
|
||||
size=(30 * sf, s.height-17),
|
||||
disabled=s.ii >= len(s.hi)-3,
|
||||
call=Call(s.mv,'ii',1)
|
||||
)
|
||||
B(
|
||||
cs(sc.UP_ARROW),
|
||||
pos=(x + 1436 * sf, 10),
|
||||
size=(30 * sf, s.height-17),
|
||||
disabled=s.ii <= 0,
|
||||
call=Call(s.mv,'ii',-1)
|
||||
)
|
||||
B(
|
||||
'Force leave',
|
||||
call=FORCE,
|
||||
pos=(x + 1469 * sf, s.height-34),
|
||||
size=(130 * sf, 27),
|
||||
label_scale=0.9
|
||||
)
|
||||
B(
|
||||
'Laugh',
|
||||
call=Call(chat,'hahaha'),
|
||||
pos=(x + 1469 * sf, s.height-62),
|
||||
size=(130 * sf, 27)
|
||||
)
|
||||
B(
|
||||
'Power',
|
||||
call=Call(push,'Power v2.5 MinUI\nExpand dev console to switch to FullUI. thanks.'),
|
||||
pos=(x + 1469 * sf, s.height-90),
|
||||
size=(130 * sf, 27)
|
||||
)
|
||||
def log(s,t):
|
||||
s.ls.append((t,NOW()))
|
||||
if s.lii < 99:
|
||||
s.lii += 1
|
||||
if s.li == s.lii-17: s.li += 1
|
||||
else: s.ls.pop(0)
|
||||
s.rf()
|
||||
def mv(s,a,i):
|
||||
setattr(s,a,getattr(s,a)+i)
|
||||
s.rf()
|
||||
def job(s,f,j):
|
||||
s.j = j
|
||||
s.lf = f
|
||||
s.hd = j[1] if s.j[0] == 'JRejoin' else j[2]
|
||||
if f is not None:
|
||||
s._job(f)
|
||||
push('Job started',color=(1,1,0))
|
||||
else: push('Job stopped',color=(1,1,0))
|
||||
s.rf()
|
||||
def _job(s,f):
|
||||
if f != s.lf: return
|
||||
s.log(f'[{s.lii:02}] [{s.j[0]}] {s.hd}')
|
||||
f(); teck(s.ji or 0.1,Call(s._job,f))
|
||||
def prv(s,c,p,n):
|
||||
s.c,s.p,s.n = c,p,n
|
||||
s.rf()
|
||||
def chk(s,pn):
|
||||
y = 0
|
||||
for n,g in s.rr.items():
|
||||
c,p = g
|
||||
if n == pn: y = 1
|
||||
else:
|
||||
for _ in p:
|
||||
if pn in [_['name'],_['name_full']]: y = 1
|
||||
if y: s.prv(c,p,n); break
|
||||
|
||||
HAS = app.ui_v1.has_main_window
|
||||
SAVE = app.classic.save_ui_state
|
||||
KICK = lambda f: DISC(f())
|
||||
FORCE = lambda: teck(0.7 if HAS() else 0.1,lambda: 0 if HAS() else app.classic.return_to_main_menu_session_gracefully())
|
||||
JOIN = lambda *a: (SAVE() or 1) and CON(*a)
|
||||
GSW = lambda s: sw(s,suppress_warning=True)
|
||||
REJOIN = lambda a,p,f: ((LEAVE() if getattr(HOST(),'name','') else 0) or 1) and teck(f() or 0.1,Call(JOIN,a,p,False))
|
||||
COPY = lambda s: ((CST(s) or 1) if CIS() else push('Clipboard not supported!')) and push('Copied!',color=(0,1,0))
|
||||
NOW = lambda: DT.now().strftime("%H:%M:%S")
|
||||
|
||||
# brobord collide grass
|
||||
# ba_meta require api 9
|
||||
# ba_meta export babase.Plugin
|
||||
class byBordd(Plugin):
|
||||
def __init__(s):
|
||||
C = Power
|
||||
N = C.__name__
|
||||
E = ENT(N,C)
|
||||
I = app.devconsole
|
||||
I.tabs = [_ for _ in I.tabs if _.name != N]+[E]
|
||||
I._tab_instances[N] = E.factory()
|
||||
1251
plugins/utilities/replay.py
Executable file
1251
plugins/utilities/replay.py
Executable file
File diff suppressed because it is too large
Load diff
37
plugins/utilities/topmsg.py
Normal file → Executable file
37
plugins/utilities/topmsg.py
Normal file → Executable file
|
|
@ -1,26 +1,31 @@
|
|||
from babase import app, Plugin as p
|
||||
from bascenev1 import gettexture as x, apptimer as z
|
||||
from bascenev1 import broadcastmessage as push, get_foreground_host_activity as ga, get_chat_messages as gcm
|
||||
# Copyright 2025 - Solely by BrotherBoard
|
||||
# Intended for personal use only
|
||||
# Bug? Feedback? Telegram >> @BroBordd
|
||||
|
||||
"""
|
||||
TopMsg v1.1.2 - Chat top right
|
||||
|
||||
When chat is muted, shows chat messages top right.
|
||||
Prevents spam and flooding screen.
|
||||
Does not repeat messages.
|
||||
"""
|
||||
|
||||
from babase import app, Plugin
|
||||
from bascenev1 import (
|
||||
get_chat_messages as gcm,
|
||||
broadcastmessage as push,
|
||||
apptimer as z
|
||||
)
|
||||
|
||||
# ba_meta require api 9
|
||||
|
||||
# ba_meta export babase.Plugin
|
||||
|
||||
|
||||
class byBordd(p):
|
||||
class byBordd(Plugin):
|
||||
__init__ = lambda s: (setattr(s,'la',None),z(5,s.ear))[1]
|
||||
def ear(s):
|
||||
a = gcm()
|
||||
if a and s.la != a[-1]:
|
||||
if app.config.resolve('Chat Muted'):
|
||||
push(a[-1], (1, 1, 1), True, s.con)
|
||||
push(a[-1],(1,1,1),True)
|
||||
s.la = a[-1]
|
||||
z(0.1, s.ear)
|
||||
|
||||
def get(s):
|
||||
with ga().context:
|
||||
s.con = x("upButton")
|
||||
s.la = None
|
||||
s.ear()
|
||||
|
||||
|
||||
z(1.0, byBordd().get)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class VeryPW(party.PartyWindow):
|
|||
def _d(s): s._p(1)
|
||||
|
||||
def _p(s, i=0):
|
||||
print(s._chat_texts)
|
||||
s._w1 = gcm()
|
||||
if s._f:
|
||||
s._o = tw(query=s._text_field)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue