#plugins-dev-chat

1 messages ยท Page 30 of 1

celest thorn
#

You can use that?

#

It WASN'T MY FAULT

upper vapor
#

i made it so you can

celest thorn
#

THEY HANDED ME THIS and told me it was something else

#

then i got really drunk fast after just a drink

#

and that night was the worst one

#

i started laughing so hard for no reason

#

i totally don't remember anything other than 2 stuff

upper vapor
#

bruhhhhh

celest thorn
#
  1. me telling my friend im trans
#

lol

upper vapor
celest thorn
#

didn't end well

#

do i care what he said, nope

upper vapor
#

some people can't grasp the existence of bisexual people

#

so

#

don't be surprised if they don't get gender identity

celest thorn
#

trust me

upper vapor
#

i fought a freaking war in youtube comments

celest thorn
upper vapor
celest thorn
#

crazy part he told me "yea don't do it, you know you would be the worst example"

#

do i care? no

upper vapor
#

don't do what

#

.?

celest thorn
upper vapor
#

right

celest thorn
#

or starting hrt

#

even tho he knows what i went through

random scaffold
#

it exists

#

lol

upper vapor
celest thorn
random scaffold
#

then why need Exiled.CustomRoles

celest thorn
#

idk

upper vapor
#

i extend the base-game HumanRole type

celest thorn
#

i didn't know HumanRole was real and could be used only on server

random scaffold
#

bruh

upper vapor
upper vapor
#

also naming it LabApi.CustomRoles is uhh

#

kinda makes it seem like it's official

random scaffold
#

xd

upper vapor
#

but the plugin itself isn't

#

oh well

random scaffold
#

in anyway labapi dont will be add custom roles

#

so its normal

random scaffold
upper vapor
#

you have one ICustomRole interface
and a CustomRole abstract class split up into 10+ parts

random scaffold
#

designed for possible expansion

upper vapor
#

putting every 3 members is

#

why

#

๐Ÿ˜ญ

#

if you already have those then why // ------------ PUBLIC INSTANCE METHODS

random scaffold
#

?

upper vapor
#

you could use #region

#

but

#

you already have a million parts

random scaffold
#

but instead of a comment, it would probably be better

upper vapor
#

but navigating this file tree also isn't very dev-friendly

#

it's your project though, just giving an opinion

#

maybe i should't be the one speaking
-# ternary operators are really cool :3

random scaffold
grand flower
#

Regions are the devil

#

If you need em you screwed up somewhere

upper vapor
#

collapsible sections in your IDE

grand flower
#

Just an organizational nightmare

worthy rune
grand flower
#

IDE already allows you to collapse methods

#

Add a healthy amount of comments and it doesn't matter if you have a huge class

#

Assuming you can't split it up, I usually split up code into components to place on a gameobject if I can (and it makes sense)

#

For stuff like a base class, if it makes sense for it to be one class, doesn't matter if it's 500 or 5000 lines long as long as it's well documented

worthy rune
#

when ever i need to find something is a class i just use this, its all in alphabetical order so its way quicker than scrolling over the entier file

grand flower
#

yeah

upper vapor
grand flower
#

I pay for Rider, I'm using all of Rider

#

I mean hey if you wanna use regions feel free to obviously, but it's just that my mentor and a few other people at the time considered them clutter and I kinda see it

hearty shard
terse bone
#

idk, i use ctrl + ,

upper vapor
#

double shift

grand flower
#

I don't see the point of hiding stuff because I generally know what I'm looking for and the rest won't bother me

upper vapor
#

less distractions

grand flower
#

I also have a very specific order for class members

#

so I know exactly where I would've placed something

upper vapor
#

yeah code arrangement is nice

#

i don't use it in Rider cuz i change my mind sometimes lol

terse bone
#

i've got tortured with StyleCop couple years ago and from that time i always write clean code

upper vapor
#

define "clean code"

true cedar
#

i wish stylecop enforced more rules tbh

#

i have to do it in my ide

#

things like file scoped namespaces, ordering of methods

upper vapor
true cedar
#

well you can't make it enforce one way or another

#

anyways

#

if anyone cares i figured out how to bypass the hint size limit

upper vapor
#

multiple

true cedar
#
string text = new('m', ushort.MaxValue - 10);
player.SendHint("{0}{1}", new Hints.HintParameter[] { new StringHintParameter(text), new StringHintParameter(text) }, duration: 10);
#

yea lol

upper vapor
#

that

terse bone
true cedar
#

idk if this is like new knowledge

#

prob not

upper vapor
#

so

#

var makes sense in contexts where the type is concrete

true cedar
#

var is great for linq and complicated type bullshit

upper vapor
#

clean code is opinionated

grand flower
#

I always use var

terse bone
true cedar
#

it depends for me

terse bone
upper vapor
true cedar
#

i only rarely use var bc its kind of frowned upon in c# but in rust you use type inference as much as possible

true cedar
upper vapor
#

guard clauses

true cedar
#

oh yea

upper vapor
#

instead of if in if in if in if in if in if

#

in for

#

in foreach

#

in try

#

in using

#

gosh, people should know about block-scoped usings

true cedar
#

i only use guard classes for simple shit like parameter validation

upper vapor
true cedar
#

clauses

#

whatever!

upper vapor
true cedar
#

or

upper vapor
#

i meant

#

using var stream = File.OpenRead

#

instad of using (var stream = File.OpenRead()) {}

true cedar
#

yea thats what im talking about

#

i only rarely see people using idisposable so

grand flower
#

try/catch in game dev ouch

upper vapor
#

the latter has some use cases
but most of the time you need the variable in the scope

grand flower
#

anytime I see one I throw it out

still thistle
#

a

true cedar
upper vapor
#

you don't use try-catch anywhere?

grand flower
#

nope, if you're using it you can probably just fix your logic so it doesn't throw

still thistle
#

i have 51,2 hours on scpsl

true cedar
#

okay

still thistle
true cedar
#

do u guys add a null check like everywhere

upper vapor
#

you still have to catch system exceptions though

true cedar
#

shoudl i do that

#

thats what the std lib does

grand flower
true cedar
#

yeah so

#

it would randomly throw errors

#

nres i should clarify

#

and break the entire coroutine

grand flower
#

doesn't anymore, but I did go through like, the entire codebase to add some null/destroyed object checks

upper vapor
#

you can use the destroyCancellationToken now

true cedar
#

it was a coroutine that was running 24/7

#

which admittedly was not the best idea in the whole world but

upper vapor
#

but there are cases where you need a try-catch

grand flower
#

What kind of cases

#

Anything Unity related you don't need to

terse bone
#

OS related stuff

upper vapor
#

yeah I/O

#

json parsing

#

yml

true cedar
#

it still pisses me off that c# doesn't have an elegant way to automatically throw nres if something is null

true cedar
#

well you have the argument null exception

#

like it exists but its

#

annoying to write the ifs

upper vapor
#

yeah

#

so you can make an extension method

#

kinda like j*va's Objects.requireNonNull

grand flower
upper vapor
#

i mean

grand flower
#

for one offs like that

upper vapor
#

if you dereference the null

#

NRE

grand flower
#

but if you have try/catch in gameplay code, you probably screwed up somewhere

upper vapor
#

true

true cedar
#

i like the rust approach where nres don't exist (for the most part)

upper vapor
#

TrySomething(..., out var result) everywhere

grand flower
#

pretty much

upper vapor
grand flower
#

null/validity checks

#

and you're good to go

#

make a Player.IsValid() extension method and it's all i need

upper vapor
#

IsValid as in..?

#

IsOnline?

#

there's an IsOffline prop but it uses the gameobject which throws...

worthy rune
#

isnt there a IsDestroyed prop

grand flower
#

not on players no

upper vapor
grand flower
#

wtf

#

well

upper vapor
#

yeah uh

#

that

grand flower
#

still would be needed since GameObject doesn't check the hub is valid before accessing

true cedar
upper vapor
grand flower
#

I made a PR for that though

grand flower
#

yeah idk what kind of naming choices were made here but like

#

bruh

upper vapor
#

get merged pls

true cedar
#

did they seriously add the dumb offline api from nwapi

upper vapor
#

so they didn't check

#

there are a lot of inconsistencies

grand flower
#
return player != null && player.ReferenceHub && player.ReferenceHub.gameObject;

IsValid

upper vapor
#

usages of null conditionals on unity objects

grand flower
#

yeah I made that mistake and was going insane as to why I was still getting NREs

#

fuck Unity

true cedar
grand flower
#

WDYM NULL PROPAGATION DOESN'T WORK AAAAAAAAAAAAAAAAAA

upper vapor
#

:3333333

grand flower
#

I'm used to it because of Unreal since everything's a pointer anyway hah

#

if (IsValid(SomeObject)) == if (SomeObject) for unity's monobehaviours

true cedar
#

oh ik

worthy rune
upper vapor
#

riptide was faster than me

grand flower
#

oh

#

right

#

I see now

#

yeah I can get rid of it heh

worthy rune
#

only brining it up because in a future PR i change all the IsDestroy method in LabAPI from Base == null || GameObject == null to just Base == null

grand flower
#

smart

upper vapor
#

๐Ÿ™

grand flower
#

fixed

worthy rune
#

also about those weird properties in Player, ill look into removing/obsoleting them

grand flower
#

I'd probably just rename it to Player.IsDestroyed

#

to be in line with all of the other wrappers

worthy rune
#

i agree, thats should be coming soon

grand flower
#

o7

#

sweet

true cedar
#

are any of u good at design i cant figure out how i want to do this shit

grand flower
#

what kind of design

true cedar
#

i have a class that is intended to be readonly (Element), and its supposed to let you have hintparameters
but you're not supposed to be able to modify or change the hint parameters once you add them (ill make a wrapper for each parameter to ensure that)
problem is how the fuck do i make that happen? i suppose i could just make an Element.AddParameter(Parameter) but that feels a bit awkward

#

actually the latter idea wouldn't be awful

upper vapor
#

so

#

the uh

true cedar
#

the uh what

upper vapor
#

you have an elements list

#

and you wanna "seal it"?

true cedar
#

nvm i explained it poorly

#

i think i know what i'm gonna do anyways

#

maybe

true cedar
# upper vapor you have an elements list

basically:
every player has a Display, this display contains a list of Elements - each element provides a string to be combined into a final hint (so its like an individual hint)
but to prevent weird behavior elements are, for the most part, readonly - if you want to update the content of one you need to create a new element
the problem is thus how do i let you add parameters to an element if its supposed to be readonly?

#

so you can't retroactively add it

#

if i make it in take in a list, you could update the list

upper vapor
#

create an ElementList class
only expose a ReadOnlyList of the elements
and make the constructors create a new list

#

you can implement IReadOnlyList or just wrap it

#

or IReadOnlyCollecction

true cedar
#

yea thats what i was thinking but

#

not a big fan of creating a new list every time

#

if only we had rust ownership

upper vapor
#

well

#

you can add an IEnumerable overload

true cedar
#

wdym

upper vapor
#

for the constructor

true cedar
#

ig

#

but no

upper vapor
#

a constructor with 1 element param, 2 element params

true cedar
#

because you could then pass in a list and modify the list

#

which the ienumerable would reflect

upper vapor
true cedar
#

OH you mean still make the list

upper vapor
#

yea

true cedar
upper vapor
#

make those immutable

#

maybe use records

true cedar
#

im using init only setters for the most part

upper vapor
#

that's good too

grand flower
#

next up on my optimization tests, gonna modify the server position distributor to do work round robin

#

odd players one frame, even players the next

random scaffold
grand flower
#

PITA to have to update large codebases

worthy rune
#

it doesnt fit well for type, and alot of rooms by default dont have one assigned so imo its abit anoying

upper vapor
#

also maybe don't rename the whole type

#

like they did with RoleType...

worthy rune
#

yeah renaming the enum type is a breaking change so kinda pointless to put a obselete on the prop

worthy rune
random scaffold
#

only like hcz049, gr18, scp127 and other

worthy rune
#

did you read what i said earlier

random scaffold
buoyant oyster
#

is there an event that fires whenever a player damages another player? I can't find it

worthy rune
#

PlayerHurt event

buoyant oyster
#

was looking under PlayerDamage

hearty shard
#

or Hurting if you want before damage happens

buoyant oyster
#

ty

grand flower
unique crane
grand flower
#

will do

#

Taking inspiration from Fortnite, they do the work round robin for player states because of how expensive doing updates for 100 players is

true cedar
#

what do you mean "round robin"

true cedar
#

ngl i dont know how much you'd gain from that

#

esp since patching a method makes it slower naturally

#

at least calling it

grand flower
#

can't be slower than like

#

the fpcserverpositiondistributor atm anyway

#

Already implemented caching for RelativePosition in FpcServerPositionDistributor.LateUpdate and it did give me some nice gains

true cedar
#

like if the player hasn't moved?

#

or

hearty shard
unique crane
#

eve..

restive turret
#

you...

hearty shard
#

can u make it so overwatch players dont count for players to start the round

modern plover
#

(Guys how the fuck do I find out why the player died)

upper vapor
restive turret
#

over on my watch

upper vapor
#

PlayerDeathEvent

true cedar
#

what the fuck why does it do that

upper vapor
#

smartwood

true cedar
#

no wonder its tanking tps for higher player counts thats 2500 a frame for 50 players

modern plover
#

Or does it..?

grand flower
#

Got a nice boost, not enormous but enough to be visible on graphs

upper vapor
true cedar
upper vapor
modern plover
upper vapor
#

UniversalDamageHandler

modern plover
#

How should I have known

upper vapor
#

contains the translation id

unique crane
upper vapor
#

yes

#

:3

modern plover
#

Yes :3

#

Okay lemme try that

upper vapor
#

also the handler should have a ServerLogsText if you want natural language output

upper vapor
#

you canc check against those

grand flower
# unique crane How about..gameplay wise?

No change in visible behaviour if that's what your asking. It's not very noticeable to players but the servers raised their average TPS on higher player counts a bit

unique crane
#

Im pretty sure that might cause issues

grand flower
#

How so

upper vapor
#

uhhhhhh

#

backtracking might take care of that?

#

not sure to what extent though

grand flower
#

Are we talking about round robin or the relative position caching

unique crane
worthy rune
#

the FPC tracer is seperate from the distributer, it creates a new relative position every 4 fixed updates

grand flower
#

tbh at a send rate of 60hz I don't think round robin would really break backtracking

#

I'll look into the FPC tracer and see if I need to patch it too

worthy rune
#

i would say its unlikely to break anything with out SL has backtracking set up

upper vapor
worthy rune
#

backtracking is super lenient in SL\

grand flower
#

yeah it should be anyway

#

We'll find out once I'm done writing the transpiler for this

unique crane
#

true..

#

Well try it and see

grand flower
#

kinda wish this loop was a for loop so I didn't have to insert an index heh

true cedar
#

AllHubs is a hashmap

#

set*

grand flower
#

what

upper vapor
#

var index = 0;
foreach ()
{
var position = list[index++]
}

upper vapor
true cedar
#

its kind of funny cause like

#

its Never used as a hashset and doesn't really have a reason to be one

#

but i guess whoever designed it wanted fast removals

grand flower
#

๐Ÿ˜ญ

#

NW please tell me you're gonna fix this

#

dunno if I can even transpile it to something else

#

probs not if there's no other list of hubs

upper vapor
#

create an int local
add 1 every iteration

#

if someone gets removed between calls
well crap

true cedar
#

u cant really

grand flower
#

forward iteration won't matter here

#

i meant replacing AllHubs but like, yeah nah

#

also for index I can probably just get away with player id

true cedar
#

u can make ur own List<ReferenceHub> ig

upper vapor
grand flower
#

praying NW fixes this ouch

upper vapor
#

i doubt they would

grand flower
#

but yeah for index I'll just create an index local and increase it every iteration

upper vapor
#

not really an internal breaking change but for plugins using it, oof

grand flower
#

I mean

grand flower
#

LabAPI plugins should use Player.List/ReadyList

upper vapor
#

benchmark

grand flower
#

shouldn't matter aren't C# bools 64 bit anyway

upper vapor
grand flower
#

might be confusing it with something else

#

but yeah a bool works too

upper vapor
#

it's 1 byte

grand flower
#

yeah I know

upper vapor
#

oh

#

arenn't

#

okay

#

i'm blind

#

wait no

grand flower
#

hahaha

upper vapor
#

nvm

grand flower
#

i meant more like

#

the operations needed to set a bool and increment an int

#

but yeah I misworded it

#

dw

true cedar
#

all types less than an int are widened

grand flower
#

right

#

checked and the IL for flipping a bool and the IL for incrementing an int are both 4 operations

#

but by using a bool I don't have to modulo it

#

so better

upper vapor
#

or you can bitmask the int with 0b1 toomuchtrolling

#

more operations though

grand flower
#

need to figure out how to add a condition to an if statement

upper vapor
#

labels

true cedar
#

what do you mean

upper vapor
#

there's no if in IL

grand flower
#

I know

#

:p

upper vapor
#

oh you mean which jump

grand flower
upper vapor
#

instruction?

true cedar
#

or brtrue

grand flower
#

aye

true cedar
#

wheres this code

icy knoll
#

me when id just do the if call inside of my method

grand flower
#

FpcServerPositionDistributor.LateUpdate

upper vapor
grand flower
#

yeah I'm transpiling this because it's already a hot path and I don't wanna make it any hotter

upper vapor
#

but wait

true cedar
upper vapor
#

ye

#

find that instruction

#

and then instruction.labels[0]

#

brfalse to that

true cedar
#

or use a codematcher (the best way of doing transpilers0

grand flower
#

yeah im using a codematcher atm

true cedar
#

yippee

#

another person converted

grand flower
#

I mean it's the most update-compatible way

#

if I start using offsets, NW updates that method and I get headaches

true cedar
#

yea

#

plus just nicer to look at it

#

nobody knows what 18 instructions ahead is

grand flower
#

so how do I get a label from a codematcher

icy knoll
#

what is code matcher?

#

i just do what exiled does for their transpilers

grand flower
#

guessing I MatchEndForward these 3 instructions and then...?

true cedar
grand flower
#

"Find those 4 instructions, then insert my instructions afterwards"

true cedar
#

codematcher.instruction.labels

#

or wtv

upper vapor
icy knoll
grand flower
#

idk not a wizard that was generated in the IL for a function call

#

not needed?

upper vapor
#

nop means "no operation"

#

literally does nothing besides wasting time

grand flower
#

๐Ÿ‘Œ

icy knoll
grand flower
#

return matcher.Instructions();

true cedar
#

.InstructionEnumeration()

grand flower
#

or that ig

true cedar
#

plus

#

its super easy to make extensions for a codematcher

icy knoll
#

ah

true cedar
#

i think they're objectively better than normal transpilers

upper vapor
#

"i think they're objectively better"

#

they're probably objectively better

#

don't think :3

true cedar
#

no

#

my opinion is always right

#

tehy are objectively better

upper vapor
#

but if it's objective then it's not really an opinion, more of a fact

true cedar
#

yeah

#

its a fact

#

they're better

hearty shard
#

pai is objective pai

icy knoll
upper vapor
#

specify the created type

random scaffold
#

why someone using transpiler

#

if exists labapi

upper vapor
#

because you can't do everything with labapi..?

icy knoll
random scaffold
upper vapor
#

CodeMatch

icy knoll
#

ohh

upper vapor
grand flower
#

if you have a single op to match it fails yeah

icy knoll
#

instead of this

new (OpCodes.Ldc_I4_1)

new Code.Ldc_I4_1_()

#

?

upper vapor
#

wha

#

no

icy knoll
#

ok

upper vapor
#

new CodeMatch()

#

also

#

Rider should let you do that

icy knoll
#

ohhh

#

right

#

ok

upper vapor
icy knoll
upper vapor
#

use the IDE, people

true cedar
#

1 sec

upper vapor
#

alt+enter
specify created type

#

does it not show that suggestion

icy knoll
#

so ur saying that this

#

does the same as this?

icy knoll
true cedar
#

MatchEndBackward puts the index at the last instruction

#

that matches that

#

don't use backwards

icy knoll
#

ok

true cedar
#

backwards looks

#

backwrads

icy knoll
#

so what do you recommend for index - 1 then?

true cedar
#

.Advance(-1)

#

or just match two instructions

#

or wtv

icy knoll
#

this is so much better

#

why does exiled do it in the other way

true cedar
#

tradition

icy knoll
#

this may make it so i actually do transpilers more

#

wtf

true cedar
#

i wrote all my transpilers for brights with them

#

u can do some really complex shit

icy knoll
#

i usually only do prefix or postfix

hearty shard
icy knoll
#

that's it

hearty shard
#

Ur my dev now thanks

icy knoll
true cedar
#

them but

hearty shard
icy knoll
#

OR ILL TAKE AWAY UR SERVER

#

:3

hearty shard
#

focus on evehints

hearty shard
icy knoll
hearty shard
#

sending hr report

grand flower
#

sanity check, if I want to pass in a local to a function call, I load the local and then call the function right

hearty shard
#

jk too lazy to do that again

icy knoll
#

hr cant do anything about me eating ur cable!! teehee

grand flower
#

someclass.function(myLocalBool)

hearty shard
#

Im too braindead to understand what ur trying to say

grand flower
#

aight awesome

#

writing a transpiler

true cedar
#

is the method static

hearty shard
#

Oh

true cedar
#

if not u need to load the class to call it on first

grand flower
#

static

#

also how do I tell Harmony I want to load a local declared earlier

true cedar
#

huh

grand flower
#

oh

#

LocalIndex

#

nvm

upper vapor
#

Ldloc(index)

grand flower
#

yeah

upper vapor
#

ye

hearty shard
#

Transpilers are interesting

#

I gotta write one...

#

For smth..

grand flower
#

don't write transpilers unless absolutely necessary

upper vapor
grand flower
#

I find them cool but also don't like them in terms of maintenance cost

hearty shard
grand flower
#

if NW updates something a transpiler modifies it could just break

hearty shard
#

Why would nw update code for round start

grand flower
#

what are you trying to do

upper vapor
hearty shard
grand flower
#

no i mean in round start

hearty shard
#

Also modify ScpSpawner and also

#

Modify the round start player count

#

Make ow not count

#

:)

#

Its just to a reason to learn transpilers

grand flower
#

it already shouldn't

hearty shard
#

False

#

It does

grand flower
#

interesting

hearty shard
#

Has been doing that since ages

true cedar
#

example

hearty shard
#

It was never changed to not count OW afaik

grand flower
#

then yeah have fun modifiying RoundSummary._ProcessServerSideCode

hearty shard
#

Is that it?

grand flower
#

yeah it is

true cedar
#

it didnt work well

hearty shard
#

I dont think thats it

hearty shard
#

Thats the after round was started

grand flower
#

that's the coroutine that checks if a round should end

hearty shard
#

Im referring to before

grand flower
#

OH

#

you mean starting

hearty shard
#

yes

grand flower
#

okay yeah I see

grand flower
#

but it works now

hearty shard
#

When round is starting if 2 overwatch players are only players on round will start and then end immediately

#

Hence why i want to change that

grand flower
#

sec

true cedar
grand flower
#

might be? what was the patch again

true cedar
#

mayhem victory thing

grand flower
#

New LabAPI event does it iirc

#

you can change the winning team

true cedar
#

oh

#

yea i love codematchers idk

#

i wish people used them more

#

newer harmony versions make them even better

grand flower
#

@hearty shard CharacterClassManager.Init

hearty shard
#

Thats not the issue

#

The issue is

#

Im in bed

#

And ive never written a transpiler before

#

So this will be fun

grand flower
#

good luck

#

@true cedar how do I get the return value of a method call in IL

true cedar
#

what do u mean

#

its automatically loaded onto the stack

#

if thats what ur asking

grand flower
#

yep, awesome

true cedar
#
ldarg.0
ldarg.1
Z call Method(X, Y) 
// z is now on stack
hearty shard
#

pai so smart

true cedar
#

so true

#

the #1 iler

grand flower
#

ah wait

#

got the wrong label

#

for skipping the current iteration

#

label i'm currently matching is ending the loop

hearty shard
true cedar
#

see and with a normal transpiler

hearty shard
#

Pai

true cedar
#

that would've taken 3 years to figure out

hearty shard
#

Can you rewrite harmonyyyy :3

true cedar
#

i WISH

grand flower
#

why rewrite perfection

hearty shard
grand flower
#

the thing even spits out IL with [HarmonyDebug]

#

i love it

hearty shard
#

Harmony is hell on earth

hearty shard
grand flower
#

yea

hearty shard
#

Damn

grand flower
#

on your desktop

true cedar
#

oh i didnt realize that LOL

grand flower
true cedar
#

i always made a LogTranspiler method

grand flower
#
### Patch: static PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData PlayerRoles.FirstPersonControl.NetworkMessages.FpcServerPositionDistributor::GetNewSyncData(ReferenceHub receiver, ReferenceHub target, PlayerRoles.FirstPersonControl.FirstPersonMovementModule fpmm, System.Boolean isInvisible)
### Replacement: static PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData PlayerRoles.FirstPersonControl.NetworkMessages.FpcServerPositionDistributor::PlayerRoles.FirstPersonControl.NetworkMessages.FpcServerPositionDistributor.GetNewSyncData_Patch0(ReferenceHub receiver, ReferenceHub target, PlayerRoles.FirstPersonControl.FirstPersonMovementModule fpmm, System.Boolean isInvisible)
IL_0000: Local var 0: PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData
IL_0000: Local var 1: PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData
IL_0000: Local var 2: PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData
IL_0000: // start original
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call       static PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData PlayerRoles.FirstPersonControl.NetworkMessages.FpcServerPositionDistributor::GetPrevSyncData(ReferenceHub receiver, ReferenceHub target)
IL_0007: stloc.0
IL_0008: ldarg.3
IL_0009: brtrue =>  Label0
IL_000E: ldloc.0
IL_000F: ldarg.2
IL_0010: callvirt   PlayerRoles.FirstPersonControl.PlayerMovementState PlayerRoles.FirstPersonControl.FirstPersonMovementModule::get_SyncMovementState()
IL_0015: ldarg.2
IL_0016: callvirt   System.Boolean PlayerRoles.FirstPersonControl.FirstPersonMovementModule::get_IsGrounded()
IL_001B: ldarg.1
IL_001C: callvirt   UnityEngine.Transform UnityEngine.Component::get_transform()
IL_0021: callvirt   UnityEngine.Vector3 UnityEngine.Transform::get_position()
IL_0026: call       static RelativePositioning.RelativePosition GameOptimizer.Patches.RelativePositioningCache::GetOrCreate(UnityEngine.Vector3 position)
IL_002B: ldarg.2
IL_002C: callvirt   PlayerRoles.FirstPersonControl.FpcMouseLook PlayerRoles.FirstPersonControl.FirstPersonMovementModule::get_MouseLook()
IL_0031: newobj     System.Void PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData::.ctor(PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData prev, PlayerRoles.FirstPersonControl.PlayerMovementState state, System.Boolean bit, RelativePositioning.RelativePosition pos, PlayerRoles.FirstPersonControl.FpcMouseLook mLook)
IL_0036: br =>      Label1
IL_003B: Label0
IL_003B: ldloca.s   2 (PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData)
IL_003D: initobj    PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData
IL_0043: ldloc.2
IL_0044: Label1
IL_0044: stloc.1
IL_0045: ldsfld     System.Collections.Generic.Dictionary`2<System.UInt32, System.Collections.Generic.Dictionary`2<System.UInt32, PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData>> PlayerRoles.FirstPersonControl.NetworkMessages.FpcServerPositionDistributor::PreviouslySent
IL_004A: ldarg.0
IL_004B: callvirt   System.UInt32 Mirror.NetworkBehaviour::get_netId()
IL_0050: callvirt   virtual System.Collections.Generic.Dictionary`2<System.UInt32, PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData> System.Collections.Generic.Dictionary`2<System.UInt32, System.Collections.Generic.Dictionary`2<System.UInt32, PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData>>::get_Item(System.UInt32 key)
IL_0055: ldarg.1
IL_0056: callvirt   System.UInt32 Mirror.NetworkBehaviour::get_netId()
IL_005B: ldloc.1
IL_005C: callvirt   virtual System.Void System.Collections.Generic.Dictionary`2<System.UInt32, PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData>::set_Item(System.UInt32 key, PlayerRoles.FirstPersonControl.NetworkMessages.FpcSyncData value)
IL_0061: ldloc.1
IL_0062: // end original
IL_0062: ret
DONE
true cedar
#

u can prob do that without codematchers

hearty shard
#

My desktop ....

#

Is hidden....

grand flower
#

F

hearty shard
#

it looks so much nicer...

grand flower
#

wait nvm the label is correct

#

goes to the end of the loop but jumps back to the start if we've still got elements

#

im stoopid

true cedar
grand flower
#

no and i won't ever look at them

true cedar
#

yea

grand flower
#

it's beautiful on the outside and it's all that matters

true cedar
#

even then

#

NOTHING IS DOCUMENTED!!

#

and the things that are have the most useless documentation

grand flower
#

also can I tell the codematcher to set its position to a specific label

true cedar
#

um

#

one sec

#

probably not

#

i mean u can

grand flower
#

eh it's fine I'll just inject the instructions when I find the label

true cedar
#

instructions.FindIndex(x => x.Labels.Contains(label))

grand flower
#

guess that'd work yeah

#

aight time to test it

#
matcher.InsertAndAdvance(
    new(OpCodes.Ldloc, isOdd.LocalIndex),
    new(OpCodes.Ldc_I4_0),
    new(OpCodes.Ceq),
    new(OpCodes.Stloc, isOdd.LocalIndex)
);
true cedar
#

why are u

#

huh

#

oh thats flipping i

grand flower
#

isOdd = !isOdd

#

wtf

#

no harmony patching exception

true cedar
grand flower
#

ah fuck

#

the IL looks fucky

true cedar
#

can i see ur codematcher

grand flower
#

dm'd

#

guess i need to move to the next instruction

#

matcher.Advance(1).Insert...

#

huh

restive turret
#

Cyn and it's transpilers

grand flower
#

im stupid it couldn't match anymore because I added my instructions

true cedar
#

lol

grand flower
#

IL looks perfect now

#

i'd test it out but dummies won't cut it since they don't walk much bleh

restive turret
#

Haha

#

254 player?

grand flower
#

100

#

how am I making it worse with this

#

nvm

#

it is better

#

without

#

okay it's gotta be some other code

#

it's only because they were captains

hearty shard
#

What did bro do

grand flower
#

probs another plugin

#

without, lemme try with

restive turret
#

Try with 254 player

grand flower
#

with

#

seems to be a bug

#

one of the QA testers doesn't see other players move

#

but another sees us fine

#

i do see some wearablesync exceptions

#

probs the dummies

#
[2025-05-25 14:44:19.063 -07:00] [STDOUT] InvalidOperationException: Unable to create WearableSyncMessage with payload of 183.
[2025-05-25 14:44:19.063 -07:00] [STDOUT]   at PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables.WearableSyncMessage..ctor (ReferenceHub hub, PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables.WearableElements flags, Mirror.NetworkWriter payloadWriter) [0x00046] in <2343be033e9f4e37923f780ece756d8e>:0
[2025-05-25 14:44:19.063 -07:00] [STDOUT]   at PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables.WearableSync.OnHubAdded (ReferenceHub hub) [0x00066] in <2343be033e9f4e37923f780ece756d8e>:0
[2025-05-25 14:44:19.063 -07:00] [STDOUT]   at (wrapper delegate-invoke) System.Action`1[ReferenceHub].invoke_void_T(ReferenceHub)
[2025-05-25 14:44:19.063 -07:00] [STDOUT]   at ReferenceHub.Start () [0x00009] in <2343be033e9f4e37923f780ece756d8e>:0
#

no exceptions but still not moving hmmm

#

ah odd players can't see anyone move lol

#

probs fucked up my logic

hearty shard
#

Interesting

grand flower
#

Gonna fix my logic but @unique crane since you wanted results of round robin ^

#

those results do include relative position caching which gives like 4-7 ticks by itself

#

but the rest is just round robin

unique crane
#

I would put it to normal round test

#

with real players

grand flower
#

yeah we will once I get that odd players logic fixed

unique crane
#

If its gonna work

#

I might ask beryl and hubert what they think about it

hearty shard
#

David when fix

restive turret
#

fix deez

hearty shard
#

BE QUIET

grand flower
#

now to figure out why the fuck my even/odd logic is screwy

#
    IL_007E: ldloc      2
    IL_0082: not
    IL_0083: stloc      2
#

kinda wonder if it's not

unique crane
#

@grand flower If you want, next up you can look at animations (IK)

#

Maybe you can optimize that trolling

#

(thats like top 1 performance heavy currently)

hearty shard
#

Can you show everything :3

unique crane
#

Uhhh tomorrow

#

Ive got final matura exam tomorrow

#

and I gotta eep well

hearty shard
#

Im gonna do horrible things just u wait

unique crane
#

):

hearty shard
#

interesting

grand flower
#

also backtracking was still working, we'll have to see with actual players (as always) but it seems like there's very little cons to this

grand flower
#

inb4 fix cheating problem with round robin /s

#

hah jk

hearty shard
#

Whats back tracker used for again

#

Desync / weird movement iirc

grand flower
#

rewinds people for hitreg

#

iirc

hearty shard
#

Or that.

grand flower
#

i'll have to check how expensive it is and if i need to patch it

hearty shard
#

I forgot about shooting

grand flower
#

but i doubt it

#

hell with round robin I don't think I'm gonna be doing much more optimization after this

plain gazelle
#

Using a raycast to look at a Pickup on the ground, how would go about to get the Pickup as a reference?
GetComponent<Pickup> on the collider?

#

@hearty shard Pickup.Get only accepts a ushort or an ItemPickupBase
-# not sure what an ItemPickupBase is

hearty shard
#

Pickup is the labapi wrapper of it

#

You might be able to Pickup.Get(GetComponent<ItemPickupBase>)

plain gazelle
#

Will try that, thank you+

icy knoll
#

if that doesnโ€™t work, usually what works for me on colliders is collider.transform.root.GetComponent<ItemPickupBase>()

#

every time I try to do GetComponent on the collider i get null so, yeah

buoyant oyster
#

ev.IsAllowed = true in Hurting event is not working for two members of the same team, I'm def missing something but idk what it is

buoyant oyster
#

FF has to be on?

#

man

teal junco
#

uh yeah

#

the game wont even attempt hurting between two players if FF isnt on

hearty shard
#

^^

#

Hurting is when damage is attempted

#

IsAllowed is always true in that case i believe

#

You'll need a work around

grand flower
#

patch in your own event

grand flower
#

@unique crane Tested with a few players, no discernible gameplay changes other than the jitter in the videos

#

The performance boost is also tied to the resources the machine has

#

If the server is given a single core, the performance boost (while there) isn't as good

#

But otherwise still a nice thing for servers that need a little boost

grand flower
#

Especially high player counts, I think you'd be able to play at a stable 30 tps w/ 100 players.

#

The issue would likely be client performance at that point

#

This is still useful for 48/64 player servers as long as you don't starve it of resources

upper vapor
upper vapor
grand flower
grand flower
upper vapor
grand flower
#

Added a bool to the method and just flipped it before it looped

#

And within the loop it keeps track if the current hub is odd or even with another bool

upper vapor
#

How do you track it between calls tho

grand flower
#

Wdym between calls

#

The bool that tracks whether the current frame should treat odd/even is a static if that's what you mean

upper vapor
#

A field?

grand flower
#

I added a condition to the loop that checks if the update should skip the player

#

Yeah

#

Sec

upper vapor
#

Ye

#

So like
ldfld State
ldc.i4.0
ceq
dup
stfld State
stloc localState

#

Not sure if the bitwise not instruction is faster than ceq, have you benchmarked it?

grand flower
#

bitwise not didn't work

#

for some reason

#

I could probably not make it a function call but like

#

negligible

celest thorn
#

what is even the round robin?

#

never heard of it

grand flower
#

multiple ways of doing it but one is you update odd players one frame, and then even the next

#

so you cut the amount of updates per tick in half

#

and then inside the loop @upper vapor

#

_isEven is the frame state, isEven is whether or not the current hub is even

#

then I just check if we should skip the hub by adding a condition

#

which is just this atm

#

although in the future I will be skipping dummies/the host player probably and other stuff
also got some plans for adaptive update rates based on the current amount of players alive

grand flower
#

what do you mean

celest thorn
#

im confused

upper vapor
grand flower
#

A way to optimize servers with high player counts

#

yeah I did like

#

Ldloc, not, Stloc, just didn't do anything, even players would never get updates and saw everybody as standing still DogKek

celest thorn
#

oh but for what aspect?

grand flower
#

define aspect

#

It optimizes the update rate of player positions

grand flower
#

by only sending updates to half of the players every tick

#

meaning your 100 player server would act as a 50 player server in that regard

celest thorn
#

interesting

grand flower
#

if you can keep a high tickrate you get minimal side effects from doing that

celest thorn
grand flower
#

FpcServerPositionDistributor.LateUpdate

celest thorn
#

interesting

grand flower
#

I've got some other patches in that function that give it some boosts

celest thorn
#

never thought of that

grand flower
#

You can thank Fortnite for it DogKek

grand flower
#

It's one of the many tricks they do to run 100 player servers smoothly enough

teal junco
#

does it only cause issues for high speeds?

grand flower
#

Yeah Epic Games are pretty damn good at that stuff

celest thorn
#

Cool asf

grand flower
upper vapor
upper vapor
#

In the loop

grand flower
#

compared to just the current four

upper vapor
#

Wouldn't you need to load the local again?

teal junco
grand flower
#

that's 255% movement speed, so like, hardly ever happens for most servers

#

and 173's jitter isn't even that bad

grand flower
celest thorn
grand flower
#

maybe if I get rid of the function call

celest thorn
#

etc...

grand flower
#

nope, was brought up by davidsebesta but it works perfectly fine

#

backtracking is lenient in SL and still holds up

celest thorn
#

but im interested to know what else you did

upper vapor
celest thorn
#

to optimize it

grand flower
#

tbf the hot path in that method is the looping, calculating relative positions and sending the data

#

and I wanna keep the function call & pass in the hub actually

#

so I can do more checks if I want to be aggressive and do stuff like skipping dummies, the host player, and other custom checks

grand flower
celest thorn
#

like you do half and half

#

for it

#

thats it?

grand flower
upper vapor
#

OptiFine for SL

#

Plugin

grand flower
#

clientside defo needs some optimization at higher counts

teal junco
grand flower
#

but we can't do it so w/e

celest thorn
teal junco
#

yes because I will make optifine for SL TrollFace

celest thorn
#

and you just strip them of it?

grand flower
#

I cache relative positions in that method so it doesn't compute them more than once per player

#

so at 48 players, it's 48 computed relative positions, not 48^2

celest thorn
#

because desync if done improprely would be crazy

grand flower
#

backtrack isn't affected by either of those fixes

celest thorn
#

waypoints get duplicated?

#

for each player?

grand flower
#

those calculations do yeah

#

even though they won't change in that loop

#

for each player combo

#

so playercount^2

#

48 players means 2304 relative position calculations

#

give or take

celest thorn
grand flower
#

with caching it's just playercount, so 48

celest thorn
#

im so confused

#

on how you remove them

#

without causing issues

grand flower
#

I just have a cache that I clear at the start of LateUpdate

celest thorn
#

on the FPC distrubution?

grand flower
#

and I patched the code to call a function that gets the cached relative position for the given Vector3 if any, or creates and caches it

#

yeah

#

The cache is allocated once, I think I set it to like, 128 elements, so in theory it never gets re-allocated

celest thorn
#

im confused

#

so you send each data

#

i just don't see issue with this code

#

im being serious

grand flower
#

check the FpcPositionMessage constructor

celest thorn
#

OH

#

i see now

grand flower
#

yeah

#

bad

celest thorn
#

so you just cache them

#

if they are missing

#

and re use them?

#

am i right?

grand flower
#

yep

celest thorn
#
        private static void LateUpdate()
        {
            if (!NetworkServer.active || !StaticUnityMethods.IsPlaying)
            {
                return;
            }
            FpcServerPositionDistributor._sendCooldown += Time.deltaTime;
            if (FpcServerPositionDistributor._sendCooldown < FpcServerPositionDistributor.SendRate)
            {
                return;
            }
            FpcServerPositionDistributor._sendCooldown -= FpcServerPositionDistributor.SendRate;
            foreach (ReferenceHub referenceHub in ReferenceHub.AllHubs)
            {
                if (referenceHub.Mode != ClientInstanceMode.Unverified && !referenceHub.isLocalPlayer)
                {
                if(!Dictionary.TryGetValue(player, out FpcPositionMessage message)
   Dictionary.Add(referencehub, new FpcPositionMessage(referenceHub))
referenceHub.connectionToClient.Send<FpcPositionMessage>(message);
                }
            }
        }
#

so something like this?

grand flower
#

nope

#

the patch for caching the relative position isn't done in that method

#

the only thing done in that method is clearing the cache at the very start

celest thorn
grand flower
#

in GetNewSyncData

celest thorn
#

48^2 because each player target each others

grand flower
#

yep

celest thorn
#

so playerA will send a packet

#

and PlayerB does the same

#

2^2 for example

grand flower
#

You send every player the position of every player

celest thorn
grand flower
#

You could if you wanted to, I just made it easier with a method

celest thorn