#plugins-dev-chat
1 messages · Page 150 of 1

why wasn’t that announced? is it not on live?
It's on early server build
It's on the early-server-build branch
It should be on public by now
someone forgot to push early-server-build int olive
why 😭
So apparently the plugin devs don't need to know about it 
Cuz idk
This is fucking insane to me
Me when jesus forgot 
what was even added in it bruh
Ts pmo
Apparently a fix to the bug I've been complaining about

I never fucking heard about it because I DIDN'T GET AN ANNOUNCEMENT
honestly im surprised your server owner never updated
That or your transpiler just didnt error
Both of them are not active
Damn
Xd
tbh i didn’t know about this either and im an api maintainer 😭
One has medical issues and the other is moving into an apartment
FUCKING EXACTLY
SpawnActive them 
Ah now it makes sense
i knew 
I'm trying to hold this shit together
Reforms are required
ah right I forgot to make the announcement lol, had an exam at the time
you werent at the time
See its really that easy
Let go of the shit
Flush it
No one ever told jesus 💀
i’m aware
just dont
Yeah the only reason I'm worked up is because I haven't slept and it's almost 6am
I've been trying to figure out what happened in this piece of code to cause players to stop taking damage from firearms
Could you put into announcements
I have no idea what the hell is causing it
Why is this a problem, you already publicize everything 
I think his issue was needing to publicize labapi
@upper vapor asked why I used a publicized LabAPI
yeah it is a serious issue, just wanted to meme about publicizing
Ya but announcements about labapi could say that yk... Theres a version available
Hello reflection abuser
time to represent
Omfg
it is in master
isnt it
I'm representing
NativeAOT which will break everything
^^^^
Um...
this was our biggest release
Not on steam I don't think
I don't even think it's in master
XD
nope, early-build is never published into public
🗣️ 🔥
Oh well
is it in early-build? weird
ye
ya
I thought I got it into master
i mean it might be in master on GitHub
Good
Booooiiiinng
You bring pain into my life
it only has ACS and no LabApi dll
biggest release in labapi story
or xml
lmao
Any fix to TimedGrenadeProjectile like @upper vapor said?
Thats basegame
Or no?
No it's not
David said it was fixed
Yip yip horray!
So was it fixed or not?
@upper vapor oh so you're just a big fucking liar
Bro
He gave you a link to david saying it was fixed in 1.1.3
14.1.3*
Was it?
We're on 14.1.4 though..
I swear he said the labapi version
"We will be pushing it to live in around 24 hours if no other issues are found." wait wasnt it pushed
Damn
I just sent the link to the duplicate issue which said this
no it wasnt
Ur fauly
😭
Fault
ah that makes sense
How dare you
So TimedGrenadeProjectile::SpawnActive spawns grenades that instantly explode because you guys forgot to check if the timeOverride was less than zero
That's it
Uh oh
You're going to cishet land
guh....
I see
cant you just set the timer manually for now
They patched it instead
I don't know the default fuseTime
I just transpiler patched it
alright...
[HarmonyPatch(typeof(TimedGrenadeProjectile), nameof(TimedGrenadeProjectile.SpawnActive))]
public class TimedGrenadeFix
{
// Currently, SpawnActive has an issue where the default timeOverride (-1) is always being set to be the remaining time
// This causes any grenade spawned to instantly explode if you don't specify an override, which is not intended behavior
// This patch fixes that problem by preventing the RemainingTime from being set if timeOverride is less than 0
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codeMatcher = new CodeMatcher(instructions, generator);
codeMatcher.MatchStartForward(
CodeMatch.Calls(AccessTools.PropertySetter(typeof(TimedGrenadeProjectile),
nameof(TimedGrenadeProjectile.RemainingTime))))
.ThrowIfInvalid("Couldn't find RemainingTime setter call");
codeMatcher.MatchStartForward(CodeMatch.WithOpcodes([OpCodes.Ret])).ThrowIfInvalid("Couldn't find return");;
codeMatcher.CreateLabel(out Label returnLabel);
codeMatcher.MatchStartBackwards(CodeMatch.WithOpcodes([OpCodes.Dup]));
codeMatcher.Insert(
CodeInstruction.LoadArgument(3),
new CodeInstruction(OpCodes.Ldc_R8, 0d),
new CodeInstruction(OpCodes.Blt_S, returnLabel));
return codeMatcher.Instructions();
}
}
It was an easy patch
It's just weird that I had to patch ts in the first place
well you didnt
Wdym
specifying time 
Wdym I didn't patch it?
you could just timeOverride:
I patched it right there
I don't have the default grenade fuse time
Do you?
"i had to patch this"
I've got no fucking clue what the default grenade fuse time is
might be
No one flamed you
yeah
Well it doesn't matter anymore cause I already patched it
Frag: 3.5
Flash: 2.8
Scp018: 80
Scp2176: 10
I apologize I'm just pressed rn
no worries
we are working on a big update right now and we are really focused into it
so if there are issues like this feel free to ping me
TimedGrenadeProjectile::SpawnActive spawns grenades that instantly explode
I brought this up to SlejmUr who asked me to open a GitHub issue
I opened the GitHub issue, to which it was closed out by Axwabo claiming the issue was already fixed and that I need to update to 1.1.3
I then found out there have been no announcements made about the release of 1.1.3
I then also find out that, no, the issue hasn't been fixed
I just wanted one line of code changed 😭
I didn't claim it was fixed
I just marked it as duplicate
All I said was "why aren't you on 1.1.3 though"
Oh well my bad
I'm gonna ask internally what happened
Ax linked to davids comment
Sorry for reading into the issue you posted
I'm losing it
It's fine I'm just tired
It's hard to even get a straight and simple answer about basic things sometimes
I appreciate that
So yeah it was fixed (apparently) but it didn't get merged
Well praise be
I think I'm gonna go eat some food before I lose it some more
there are plenty of stuff to lose it
@slate flume here some that i checked , lmk if i skipped smth
Fire thank you brother
I don't mean any hate or disrespect or anything else to anyone with any of my earlier comments I'm just very frustrated with a bunch of stuff right now and this was another log to the fire
Was not expecting so much shit to come from inquiring about a one line change in the code
3 lines actually (because of stylecop)
Ah hell nawh
I hadn't heard about stylecop until like 2 days ago and now I've heard it 4/5 times
Be free
Still not gonna use it but I know about it now
Don't let some analyzer tell you that you need trailing commas in multiline statements
tbh I dislike stylecop
Real
and as I saw ax too lol
I dislike a lot of forced coding styles and preferences and shit
I dislike any cop 
Based
real
É
I've only had bad experience with police officers
Except for my school's SRO
He was chill
I dont really care about how my code style is going , but the docs change is something i usually try to enforce in my future and thats it
Fair
I've never written XML docs
[Accept suggestions and resolve all threads]

🔥
I think you're too harsh of a critic on yourself
Legit didn't know English was your second language
You're much more articulate than most non-primary English speakers I've met
You probably know more English words than some Americans
And all they know is English lmao
Lmfao
Wtf is a kilometer
the fact that is i can write english good because i have time editing what i was gonna say but i usually just ghasping what i was gonna try to say
because my mind is always faster than what i say so i just skip words or required context sometimes
English is a somewhat inefficient language so that's entirely fair
It urks me how long it takes some people to get the the fucking point of whatever they're saying
Like dude spit it out
and because i can just quickly switch between topics sometimes people just say "what?"
happens in hungarian too
ye , the amount of words can describe one thing but still doesnt make sense it just nyeh
My dad yells at me all the time for speaking too fast
It doesn't help that he's also like half-deaf
i just mumble most of the times
Te patkány, milyen jó napunk van ma
People just need to keep up honestly
Doesn't help when some people are approaching eminem-level speeds
MOND MEG NEKI
One time I had an interview and I had to ask the interviewer a total of 5 times to repeat what they said
Blud was just
Logicering the words
Minigun
Xd
I usually rephrase the question so i know i understood it correctly
Genius machine
😭
Just get better 
It’s ok I’m still braindead half the time. Even when somone speaks perfect English I still go 
@limber silo talk!
Thank u so much
because jesus was busy at the time it actually came out
forgot to do the usual stuff
false
you can prove it?
You sent the trollface emoji after it
so you can't 
nah im joking i use it for searching methods
Search deez
People forogor
nah
do you guys use an assembly publicizer?
Yes
i just use bepinex
Yes
Why not monomod?
i use bepinex
because easier idk
bepinex is a 1 liner in csproj
smb
smb?
Shaking my bytes
Wait no it should he shocking my bytes
is there a tutorial on how to use it?
In their site ye
Bep when he enters x or something idk never read the book
This chat is dead
well let me revive it then
is there a method that automatically gets a random room? or do i have to randomize the list
Room.List.RandomItem()
that isn't in labapi tho...
unless added recently?
no?
i think the RandomItem extension is from the base-game
it has been since forever
no from C#
itself
there isn't a reference to c# having that method
On List<T>
ahh
Actually
well Room.List is a IReadOnlyCollection so i dont think it works
we could probably make an extension for IReadOnlyCollection
nah it works
You could
where is it from?
well
If it does exist then basegame, secretapi and exiled dont need one
However all 3 have extensions related to random item (basegame for array/list, secretapi/exiled both do for IEnumerable afaik)
None of them would be needed if C# had it built in
IEnumerable isnt ideal as you have to enumerate over all items to count the length(which is requires if you want to get a random item)
min interface that fits is IReadonlyCollection
if is list use list otherwise convert to list
thats still enumerating the items
Tysm!
True...
But it does work for all, which was the point when i made it originally
btw i think Enumerable.Count casts to IReadonlyCollection in the implementation if it can(could be wrong)
There is no .Count afaik
Its .Count((
()
Method
Rather than property
Might be wrong
same thing
When she enumerate my element and I’m epic
what..
tbh that's left to the whoever uses the extension method to remember
I know Rider warns you about this, at the very least
So you can just ToList() before getting a random item
I'd still implement it as IEnumerable just for flexibility
checked and it does, i guess readonly isnt needed since all collections are mutable anyway
oh yeah thats nice, i image the perf different would be significant so its good to avoid it
checked keyword prevents it looping back to negative right
heh
I remember the one time I had to use unchecked because Rider couldn't figure out my logic wouldn't ever overflow
I use that with mirror :3
const ushort
public static byte? GetAvailableIdentifier()
{
// Unchecked because we can't overflow a byte with values between 0 - 255
// Two less instructions, yippee.
unchecked
{
var available = Enumerable.Range(byte.MinValue, byte.MaxValue)
.Except(GetOccupiedIdentifiers());
// Won't cause issues in this case - we know what we're enumerating.
// ReSharper disable PossibleMultipleEnumeration
if (available.Any())
{
return (byte?)available.First();
}
// ReSharper restore PossibleMultipleEnumeration
return null;
}
}
that was before we could change the volume of speaker toys
we'd just spawn multiple with the same controller id to increase the volume
this
😭😭
amplify your input (if possible)
eh now we can change volume so it's fine
Conversation Curveball: How stable do you expect the plugins.scpslgame.com web API will be?
Made a POC updater that uses it to find new versions of plugins without additional action by the plugin dev.
https://github.com/tayjay/EasyUpdater. Just because.
Feel free to fork/fix/rename it, I'm unsure how far I'll take it
As long as cloudflare doesn't force a check I imagine it would be fine
Good point
1000000th plugin updater 
I know how lazy I am with integrating with other plugins, so figured I'd see if there was a way to do it without needing to do anything
Yeah probably
Just hope you have fast internet
😭
More of a meme plugin at the moment I guess
💀
newtonsoft.json :((
Do you have a prefered one?
system.text.json
and System.Text.Json

this gets rid of your async issues, if you don't know how to handle async without turning it sync I'd just use that
are y'all not using system.text.json? 😭
I am for my own stuff
I knew there would be one, but couldn't find the library before
outside of SL, don't think I needed json in SL
ofc you do cyn, not a question
tbh System.Text.Json is a bit more finnicky
why


It's like, less lenient about the JSON you give it compared to JSON.NET
but once you fix it a little it's fine
For one of my side projects I had to pause I used System.Text.Json's NativeAOT stuff
it's cool
like casing for example?
I don't remember exactly
or whih oart
I think for one it doesn't like ints with decimals
1.0 wouldn't parse to an int for example
even though it's perfectly round
☠️
that pissed me off for a while
had to ask the sole Garry's Mod maintainer to fix the JSON functions LOL
thankfully he did pretty much the next day so I love that guy
also my temporary bandaid fix for that was to replace .0" with "
W move
i guess you could've made a custom converter but yeah replace works ig
now do it with spans 
was way more of a pain in the ass to do it on the backend side
since it was an ASP.NET backend
y u p
kinda sad how you can't change the defaults
that's why I just did the bandaid solution on the gmod lua side and then removed it when the maintainer fixed it
but I'll just have to remember about this issue for my project when I expose JSON to Luau

wrote some funky C++ to detect recursion in userdata parents
so like if you had a userdata A that had userdata B as a parent, but B has A as a parent

The compiler already catches that but the error was a bit hard to read, so I made my own detection to get a nicer one

yeah that does not tell me anythign
better than what the compiler used to say
This just tells you that the constraints of not having a recursive base isn't satisfied
Which should be enough for you to go "oh fuck I have a circular base"
imagine if anyone uses livestream thing which I made for audio player api lol
and what will you do if they do?
Bro I don't even want to get into that fucking mess that yesterday was
Of course! Happy to help :)
I wonder if this was ever fixed
Also I need to get into LabAPI support cause I'm about to crash out trying to figure out what's going wrong
don't think so
I think Bright's still having the issue
I'd have to check logs later
whats the issue
i could try helping you
I'm spawning a primitive and a dummy when a player dies and for some reason this makes it so when the player spawns back in, they take no damage from firearms
I get no errors in the console, no errors in the LocalAdminLogs
can you show the code
Yeah but I'm laying in bed right now
can you go to touch grass
Random thought: Would a Dummy be damaged if you spawn it behind the Player and shoot the player?
Probably
I can test
Bullet holes were going right through the player
That rules out hitbox issues possibly
The raycasts just aren't hitting
if so, then possibly the hitbox is lost somewhere
I know it's in this section of code because when I removed it the problem was fixed
which section of code
code?
anything useful
Give me a sec I have to get on my PC
code
code
The problem is in a component I made
All of our discord webhooks are broken qwq
HttpClient.GetAsync("example.com") works totally fine, but anything going out to discord.com times out :c
Is this a Discord issue, Terabit issue or skill issue on our side
public class GhostAnimation : MonoBehaviour
{
private FirstPersonMovementModule FPMM;
private Fade Fade;
private ushort Frames;
private const ushort DisappearStart = 90;
private const ushort MaxFrames = 150;
private Vector3 DeltaPos;
private float FadeIntensity;
private float FadeIntensityIncreasePerFrame;
public void Init(ReferenceHub ghost, Vector3 endPosition)
{
FPMM = ((IFpcRole)ghost.roleManager.CurrentRole).FpcModule;
Frames = 0;
DeltaPos = (endPosition - FPMM.Position) / MaxFrames;
Fade = ghost.playerEffectsController.GetEffect<Fade>();
ghost.characterClassManager.GodMode = true;
FadeIntensity = Fade.Intensity = 120;
FadeIntensityIncreasePerFrame = (255 - FadeIntensity) / (MaxFrames - DisappearStart);
FPMM.Motor.GravityController.Gravity = Vector3.zero;
}
public void Update()
{
if (Frames++ >= MaxFrames)
{
Destroy(gameObject);
return;
}
FPMM.Position += DeltaPos;
if (Frames >= DisappearStart)
{
FadeIntensity += FadeIntensityIncreasePerFrame;
Fade.DisableEffect();
Fade.Intensity = (byte)Math.Round(FadeIntensity);
}
}
}
Also this code kind of sucks right now
what piece of code fixes it?
Not using the component fixes it
just check for exceptions in local admin logs
public override void OnPlayerDeath(PlayerDeathEventArgs ev)
{
if (ReferenceEquals(ev.Player?.ReferenceHub, null))
return;
if (!Physics.Raycast(ev.OldPosition, Vector3.down, out RaycastHit hit, 10, ~LayerMask.GetMask("Ragdoll")))
return;
Vector3 up = hit.normal;
Vector3 floor = hit.point;
if (Vector3.Dot(Vector3.up, up) < 0.7)
return;
float height = 0.7f;
float length = 0.2f;
Quaternion rotation = Quaternion.FromToRotation(Vector3.up, up) * new Quaternion(0, 1, 0 ,0) * RemovePitchFast(ev.OldCameraRotation);
Vector3 position = floor + up * height / 2;
var gravestone = PrimitiveObjectToy.Create(position, rotation, networkSpawn: false);
gravestone.Type = PrimitiveType.Cube;
gravestone.Color = new Color(0.15f, 0.15f, 0.15f);
gravestone.Flags = PrimitiveFlags.Visible;
gravestone.Scale = new Vector3(0.5f, height, length);
gravestone.Spawn();
var text = TextToy.Create(floor + up * height * 0.7f - rotation * Vector3.forward * (length / 2 + 0.001f), rotation, networkSpawn: false);
text.Scale = new Vector3(0.5f, height, length);
text.DisplaySize = new (100f, 100f);
text.TextFormat = "<align=center><size=35%><b>RIP";
text.Spawn();
ReferenceHub ghost = DummyUtils.SpawnDummy("Apparition");
Timing.CallDelayed(Timing.WaitForOneFrame, () =>
{
ghost.roleManager.ServerSetRole(ev.OldRole, RoleChangeReason.None, RoleSpawnFlags.None);
ghost.TryOverrideRotation(QuaternionToPitchYaw(ev.OldCameraRotation));
//ghost.playerStats.GetModule<AdminFlagsStat>().SetFlag(AdminFlags.Noclip, true);
ghost.TryOverridePosition(ev.OldPosition);
ghost.gameObject.AddComponent<GhostAnimation>().Init(ghost, ev.OldPosition + Vector3.up * 2);
});
}
Literally nothing
That's why I'm baffled
add a delay after setting the role
before initializing the component
Okay
0.1 is assured to work
we love delay based fixes
I'm doing 1 second to be safe
-_-
Yeah so a delay didn't do anything
did you try doing the rotation & position override after the delay too
I took everything after setting the role and delayed it by a second
And it fixed nothing
so from where you think the problem starts?
The component
just comment out code until it starts working
.
inside the component
Sure
Intensity enables the effect
Also what layermask are items on?
I want to exclude them from my raycasts
What is the name
~LayerMask.GetMask("Ragdoll")
LayerMask.LayerToName(9)
I could but it's inconvenient as shit with what I already have
Yes
It's InteractableNoPlayerCollision
I commented out the code that runs in the update cycle and the problem disappeared
What the hell
why you disable and then reneable it?
I have an effects manager that patches a bunch of northwood code and allows for concurrent effects
maybe then the FPCC.Position?
Hey look I fixed it
public class GhostAnimation : MonoBehaviour
{
private FirstPersonMovementModule FPMM = null!;
private Fade Fade = null!;
private ushort Frames;
private const ushort DisappearStart = 90;
private const ushort MaxFrames = 150;
private Vector3 DeltaPos;
private float FadeIntensity;
private float FadeIntensityIncreasePerFrame;
public void Init(ReferenceHub ghost, Vector3 endPosition)
{
FPMM = ((IFpcRole)ghost.roleManager.CurrentRole).FpcModule;
Frames = 0;
DeltaPos = (endPosition - FPMM.Position) / MaxFrames;
Fade = ghost.playerEffectsController.GetEffect<Fade>();
ghost.characterClassManager.GodMode = true;
FadeIntensity = Fade.Intensity = 120;
FadeIntensityIncreasePerFrame = (255 - FadeIntensity) / (MaxFrames - DisappearStart);
FPMM.Motor.GravityController.Gravity = Vector3.zero;
}
public void Update()
{
if (Frames++ >= MaxFrames)
{
NetworkServer.Destroy(gameObject);
return;
}
FPMM.Position += DeltaPos;
if (Frames >= DisappearStart)
{
FadeIntensity += FadeIntensityIncreasePerFrame;
Fade.DisableEffect();
Fade.Intensity = (byte)Math.Round(FadeIntensity);
}
}
}
Spot the difference
missing networkserver.destroy?
I was using UnityEngine.Object.Destroy before
but also why are you using networkserver.destroy
Cause that's what DummyUtils uses
This was actually awful
Idk why UnityEngine.Object.Destroy on a dummy caused a seemingly unrelated player to stop registering damage from firearms
Idek how tf that happens
Is there any easy way to remove the Dummy badge from a dummy?
Wait nvm
I'm just gonna edit the PlayerDisplayInfo
The tag is given from it being a DummyNetworkConnection
Lame
You can hide them from the player list
But yeah it'll always have a dummy badge in-game
I'm giving it a different DummyNetworkConnection
Cause hiding the badge from playerdisplayinfo isn't working for some reason
Which API maintainer should I @ about this new bug I found
Not the one I found with Destroy
It's a different one
Well actually I'm not sure if it's NW or LabAPI
And I'm not sure if dummies consitutes base-game territory
Or if that's something that should go to LabAPI
iirc I've hidden it before
I'm about to hide it I'm just making a bug report
It's pretty easy actually
I think i just set the text to string.Empty
Yeah but that sets it for all dummies
And that's not what I want
https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/2116
This is probably the lowest priority issue on the board
tfw only 32k dummies
Lmao
This is ultimate programmer humor memorialized in a bug report
I need 2.1 billion more dummies

I need 32 thousand more speakertoy channels
you guys will never understand how it feels
This is actually kind of important because we only have 256 controllerIds
So are capped at 256 unique SpeakerToys
Ive talked about this before but people just clown on it because like 99% of the time you only need like 5
but like
itd be nice
yk
But for servers that do shit like
Yk
Replace CASSIE
theres gonna be a point where a lot of plugins use audio
It might happen soon. But that kinda builds up
Yeah I mean there's no way there's not a use case where someone is using more than 256 unique SpeakerToys
You can ward this off with a lot of clever tricks like delegating more than one speakertoy to a single controllerID, or doing audio culling, or delegating one controllerID to multiple purposes that wont overlap for one player
But ideally you wouldnt need to do all these tricks lol
audioculling is kinda underrated tbh
Also, some plugins (like Amert) are user oriented, not programmer, and when you play a sound through it, each individual one takes up a controllerID
A server host who cannot program might end up with a situation where 256+ Amert sound effects are playing at once for whatever reason, and on top of other plugins with their own audio channels, it will cause issues
its super edge case though, and maybe eventually I will have saved enough bytes worth of internet transmissions through the controller ID being a byte instead of ushort to buy a coffee
Well also like
SCP prox chat
That's another few controller IDs used up
Yeah
I think Northwood should have a basegame controllerID pool or something for plugin devs to use
because I am sick of two plugins who arent aware of each other's existence (like scp prox chat and AudioPlayerApi) sending different sounds thru the same channel
And I literally cant be fucked to modify it so they do
^ Is this outlandish for some reason I cant see
but basegame would be nice yeah
I did SpeakerToy extension methods for exactly this purpose
Honestly I have no idea how to do this. Like for audioplayerapi it may be simple enough, but if youre using AudioTransmitter from LabApi, or someone is using basegame or directly using LabApi wrappers for speakers, I dont think that gets properly registered in any way
public static byte[] UsedControllerIds => SpeakerToy.List
.Where(toy => !toy.IsDestroyed)
.Select(toy => toy.ControllerId)
.ToArray();
public static byte NextAvailableControllerId
{
get
{
var used = new HashSet<byte>(SpeakerToy.UsedControllerIds);
for (byte i = 0; i < byte.MaxValue; i++)
{
if (!used.Contains(i))
return i;
}
if (!used.Contains(byte.MaxValue))
return byte.MaxValue;
throw new InvalidOperationException("No available controller IDs remaining.");
}
}
public void AssignNextAvailableControllerId() => speakerToy.ControllerId = SpeakerToy.NextAvailableControllerId;
I have a better one sec
Hm
/// <summary>
/// Gets an enumerable which contains all occupied identifiers for audio components.
/// </summary>
public static IEnumerable<int> GetOccupiedIdentifiers() => SpeakerToy.List
.Select(s => s.IsDestroyed ? -1 : s.ControllerId);
/// <summary>
/// Returns the first available controller id that can be used for audio components, or null if none are available.
/// </summary>
public static byte? GetAvailableIdentifier()
{
// Unchecked because we can't overflow a byte with values between 0 - 255
// Two less instructions, yippee.
unchecked
{
var available = Enumerable.Range(byte.MinValue, byte.MaxValue + 1)
.Except(GetOccupiedIdentifiers());
// Won't cause issues in this case - we know what we're enumerating.
// ReSharper disable PossibleMultipleEnumeration
if (available.Any())
{
return (byte?)available.First();
}
// ReSharper restore PossibleMultipleEnumeration
return null;
}
}
Doesn't this use more memory allocation?
You're working with ints instead of bytes directly
And it also doesn't early return when it finds a non-occupied member
you initialize a new hashset
So would that make it potentially slower too?
not enough to matter compared to using a hashset
Really?
might be able to optimize it a tiny bit but like, this isn't gonna be used in a hot path anyway
I'm gonna stand by this one
I use HashSet for O(1) lookups
also
they're enumerables
they're lazily evaluated in this case, so Any() returns true immediately because there's an element
and we return the first one that isn't excepted (GetOccupiedIdentifiers())
afaik
Also your range is missing byte.MaxValue
So you're checking 255 controllerIDs, not 256
You'd have to stack these side by side in a performance test for me to be convinced this is a lot less optimized
not a lot less optimized, but probably a bit slower?
yup, will fix
The use of ints isn't convincing to me
why
More memory allocation
it's on the stack
public static byte NextAvailableControllerId
{
get
{
var snapshot = SpeakerToy.List.ToArray();
var present = new bool[256];
foreach (var t in snapshot)
if (!t.IsDestroyed)
present[t.ControllerId] = true;
for (ushort i = 0; i <= byte.MaxValue; i++)
if (!present[i])
return (byte)i;
throw new InvalidOperationException("No available controller IDs remaining.");
}
}
I think this is better than both
So just
public static byte GetNextAvailableControllerId_StackAlloc()
{
var snapshot = SpeakerToy.List.ToArray();
Span<bool> present = stackalloc bool[256];
foreach (var t in snapshot)
if (!t.IsDestroyed)
present[t.ControllerId] = true;
for (ushort i = 0; i <= byte.MaxValue; i++)
if (!present[i])
return (byte)i;
throw new InvalidOperationException("No available controller IDs remaining.");
}
public static byte NextAvailableControllerId => GetNextAvailableControllerId_StackAlloc();
Probably the least overhead
Well
Toarray still isn't pretty
So
public static byte GetNextAvailableControllerId_StackAlloc()
{
Span<bool> present = stackalloc bool[256];
foreach (var t in SpeakerToy.List)
if (!t.IsDestroyed)
present[t.ControllerId] = true;
for (ushort i = 0; i <= byte.MaxValue; i++)
if (!present[i])
return (byte)i;
throw new InvalidOperationException("No available controller IDs remaining.");
}
Put that in the getter
public static byte NextAvailableControllerId
{
get
{
Span<bool> present = stackalloc bool[256];
foreach (var t in SpeakerToy.List)
if (!t.IsDestroyed)
present[t.ControllerId] = true;
for (ushort i = 0; i <= byte.MaxValue; i++)
if (!present[i])
return (byte)i;
throw new InvalidOperationException("No available controller IDs remaining.");
}
}
why do you throw exception instead of returning null?
Because there is no controllerID available and returning null requires making the return byte nullable
makes sense
yeah okay but at this point just use the Enumerable solution
public static byte NextAvailableControllerId
{
get
{
Span<bool> present = stackalloc bool[256];
foreach (var t in SpeakerToy.List)
if (!t.IsDestroyed)
present[t.ControllerId] = true;
for (byte n = 0; n < byte.MaxValue; n++)
if (!present[n])
return n;
if (!present[byte.MaxValue])
return byte.MaxValue;
throw new InvalidOperationException("No available controller IDs remaining.");
}
}
Is probably the best it gets
You're pretty much doing the same just a little more janky? When C#'s providing you exactly what you need
You're also adding another branch with the if (!present[byte.MaxValue])
Would that end up being better or worse than making n a ushort?
i mean
The way it's done is on the stack, there's no GC pressure

Yeah you're probably right
Keep in mind the compiler is also smart
This is pretty good
Probably the best optimization without sacrificing readability
Just write it in assembly atp
Should I make a bit manipulation version? 
I'd shoot you if you worked on my codebase

You're not calling this 10000 times a second
And even if you were it probably wouldn't be expensive anyway
Hyper-optimizing one controllerID lookup
hyper optimize it all
Okay but in all seriousness I actually really like this one
To me it just feels better than the Enumerable
It needs to be hyper optimized
Yours might be a bit more performant, a bit less performant, idk
Whats the point of C# if not optimizing to the maximum
Binary 
loopop
I'm gonna steal so much code off of stack overflow
Can't wait for it to you to crash out on it
why bother stackallocing why not create a new bool array
hope we are all doing well
Yesterday was a clusterfuck but today's a new day
indeed, hope things go better today
anyways you could probably speed this up by using simd
present.IndexOf(false) is likely faster
Not sure how tf this works but I stole it from stack overflow
// de Bruijn lookup table for 64-bit trailing-zero.
private static readonly int[] DeBruijnIdx64 = new int[64]
{
0, 1, 48, 2, 57, 49, 28, 3,
61, 58, 50, 42, 38, 29, 17, 4,
62, 55, 59, 36, 53, 51, 43, 22,
45, 39, 33, 30, 24, 18, 12, 5,
63, 47, 56, 27, 60, 41, 37, 16,
54, 35, 52, 21, 44, 32, 23, 11,
46, 26, 40, 15, 34, 20, 31, 10,
25, 14, 19, 9, 13, 8, 7, 6
};
// Trailing-zero count (returns 0..63), or 64 if v == 0
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int TrailingZeroCount64(ulong v)
{
if (v == 0) return 64;
// isolate lowest set bit
ulong isolated = v & (ulong)-(long)v;
// multiply by de Bruijn and shift
int idx = (int)((isolated * 0x03F79D71B4CB0A89UL) >> 58);
return DeBruijnIdx64[idx & 0x3F];
}
Exactly
why
me when im in an overengineering competition and my opponent is ThatGuy
Lol
only paws and thatguy would do this
overengineering is fun
holy macaroni
Nah, I'd win
technically tho u could make this even faster with a switch statement
prob
Remind me to blacklist every single one of you sinners from my codebases
my poor babies are going to be violated
I don't do it in invidual methods (unless peformance critical), but I do overengineer my features
Span<ulong> words = stackalloc ulong[4];
words.Clear();
// Build bitset: 1 = used
foreach (var t in SpeakerToy.List)
{
if (t.IsDestroyed) continue;
int id = t.ControllerId;
int wi = id >> 6; // id / 64
int bit = id & 0x3F; // id % 64
words[wi] |= 1UL << bit;
}
// Scan words for first zero bit (free spot)
for (int wi = 0; wi < words.Length; wi++)
{
ulong freeBits = ~words[wi];
if (freeBits == 0) continue;
int tz = TrailingZeroCount64(freeBits); // 0..63
int candidate = (wi << 6) + tz;
if (candidate <= byte.MaxValue)
return (byte)candidate;
}
throw new InvalidOperationException("No available controller IDs remaining.");
I think this works?
What the fuck am I writing
meh
please get some help
why do you even use stackalloc, just make a private static field
you could just treat it as a Span<ulong> and rely on simd
or Span<int>
something like that
hashsets/maps usually do that
Isn't simd supposed to be good for really big arrays and like parallel work?
Small arrays it doesn't really matter
I mean, at this point just hard-code every value in a binary search with < and >
its still one instruction
also unecessary locals, smh, remove wi and bit and just do one giant bit operation
What would be the use case here
We're not operating on a bitset, we're scanning a bitset
you can still use simd to scan a bitset lol
swiss maps do it
I feel like this is one of those cases where it's like quick sort vs merge sort
It depends on the size of the bitset
This bitmap is small
And also I suspect it allocates shit too
Bad
what u do is probably fine is and is effectively SWAR
but actual simd might be work better
All this effort, just for SL to negate it all in one movement tick
also, like why are we foreaching every speaker toy then for ing over whatever that span is, just foreach every speaker, & by the ~ of the id, then for each byte for a non-zero value
like what are we even doing
although yeah you could literally just keep track of the smallest value
the span idea is cool n all for less memory usage, but I think the fastest method should be only one iteration over every speaker toy
No
so one foreach
no more fors or whatnot
I think tracking every value at once, then &ing by the ~ is the best way tho cuz you track all values at once, then you just find a non-zero value
That's because that would mean more operations iirc
I'm sorry, are all my ALUs potatoes???
it depends on the use case but im psure this would work fije
I didn't know bit manipulation was so inefficient
the "overhead" they're referring to afaik is because you need to fit simd data within lanes
Wait what am I talking about
I don't use the controllerID itself because this is essentially a list of bool values
but you have what is either a supported lane count or can easily be divided into one
We find the place in memory and shift the corresponding bit
but why not just
bruh
loop once keep track of the smallest value
do I gotta draw this out
no?
the only advantage i can think of is fewer branches
we can use 0, 1, 2, 3 etc... but not 255
and then what
0's used up, what do we do
it's the smallet value
I'm confused
This is effectively just exactly what I'm doing
Hi confused
bro you're checking for trailing zeros for some reason 😭
Yeah because I invert it
no i get why he's doing that
Then use an efficient method to find the first non-zero
also don't use a for loop in this case
ulong freeBits = ~words[wi];
mfw when > 0
unroll the loop
What?
just check if the value is greater than 0 if you're checking for non-zero values 😭
I need to find where in the bitmap it's 0
Otherwise I don't get an id
My words count is 4 ulongs
Also true
then use a for loop
Foreach is faster
I did
On the words
Then I find the non-zero in the fastest way
thats not unrolling
unless jit does it for u
it might idk
You mean write it all out separately?
yea
Facts
unchecked code is also faster iirc
so u can try adding that
god i love micro optimizing
I wanted to hear a little about the shit I stole
In combinatorial mathematics, a de Bruijn sequence of order n on a size-k alphabet A is a cyclic sequence in which every possible length-n string on A occurs exactly once as a substring (i.e., as a contiguous subsequence). Such a sequence is denoted by B(k, n) and has length kn, which is also the number of distinct strings of length n on A. Each...
What
Okay boss
Omg a number
urm wtf

rip
Lmao
idfk
why is he a deleted user now wtf
what did u see
.
the dude deleted himself
who
im psure it takes like
a week for someone to delete their account
and during that time you can't use it
wtf did he do
ThatGuy
lmfao he actually went poof
@slate flume
?
he exists?
probably
except in dms still looks fine
hes in our server tho??
they 86'd him
def discord moment
i think he actually got deleted
Or he force deleted himself
only in plugin chat istg
odd
!getuserinfo 434572461011501067
no I see it in dms
odd
actually the server he devs for, in general somebody said his acc got disabled by discord
so I guess it was intentional?
weird
If you violate ToS or eual or smth ye you get no time for it
You get immediate action
what did my boy do

😭
no but this shit only happens in plugin chat
aint no chat like a plugin chat
in java for sure
!getuserinfo 434572461011501067
I heard spawn queue numbers (4013...) have a bug now. Is there any way to change it via plugin?
i might add support for event-based animations
i want sans to do his aura empty eyes whenever the player he's attached to pulls out a gun or something
You better be using the arguments SyncList for this
If you aren't I'll make Exiled steal your house 
lol i like that
Synclist?
PS if anyone has high quality back facing versions of sans battle sprites please lmk
rn his back just says "sans; front on other side"
It’s a member of the TextToy class, do you not know what it is?
No, I don't work with TextToy directly
is it just determining who gets sent this info?
What wrapper do you use?
It's an MER schematic
No it acts as parameters for a string.Format call
I’ll pr it to PMER soonTM if it’s not implemented
So what would be the ourpose here
just for instance
Add a white pixel and a black pixel, then every pixel can be {0} or {1}
So less networking
I’ve done a lot of shenanigans with text toys lol
^ Synclist in this specific case is probably like uber specialized. If I end up making more pixel things though, I can consider figuring out a way to directly generate optimized pixel art text toys
at runtime or whatever
I did this with primitives, but I can now do it with text toys
I don't have the time to spend making specialized solutions to every problem i have anymore. It is very sad
What is the limit of synclist
can I put like 100 elements in it?
then I have hyper optimized 100 color images
No limit, though it has to sync when new clients join
Yeah
Luckily I dont worry myself about optimization
As long as I can't tell the TPS is dropping without checking I'm usually happy enough.
The biggest problem i've ever had is doing TextToys client side, I know its possible
but SyncList don't allow me and they are just a pain in the ass
😭 😭 😭
Me when SecretLabNAudio has that
The only 2 apis for audio and the competitor one isn't updated so
Did you know that numbers in C# are padded to at least 4 bytes anyway
-# why am I replying to a deleted user
not for long
Updated to what




