#world-persistence

1 messages ยท Page 4 of 1

quick imp
#

Hows this?

visual cargo
#

almost I think you want OnPostSerialization to be OnDeserialization
this will currently just run twice for the sender

wary summit
# quick imp Hows this?

kinda hard to tell without the larger context, but even then I don't think the OnPostSerialization is utilized correctly.

I'd recommend using the method described in both of these videos above, where ApplySerialization or HandleSerialization is it's own separate custom event that you make, and is called both in ondeserialization and also immediately after you run requestserialization

visual cargo
#

I wonder if someone's made a chart for the network functions and who runs them and their order.... maybe I should make one

visual cargo
wary summit
visual cargo
#

well yeah but I'm personally just not a video learner. I like hundreds of pages of manuals and charts and stuff

#

I get impatient

quick imp
#

Ahhhhh lets see...

#

I assume serialization is the packing of data to go glocal and deserialisation is once its been decompressed and applied?

quick imp
#

Alright so im guessing the weapon change will be visually delayed for everyone else but besides that we guuchi?

wary summit
#

only problem then is that udon graph has a shitty bug which makes these kinds of structures not super reliable. Which is why I'd recommend applyserialization being a separate thing which both of these sources send a custom event to run

quick imp
#

By not being reliable what would that entail?

wary summit
#

the compiler might not include the variable functions on the second one

#

so it would just Gameobject.Setactive null, and crash

quick imp
#

Oh i see, that would be pretty crap

#

Ahh so Im guessing Id put deserialisation further back in the graph?

#

Or forward

#

left

wary summit
#

whatever location works to make the structure look like this

quick imp
#

I see :L

quick imp
#

ops forgot to plug in the set itemnumber on the custom event but yeye

wary summit
wary summit
# wary summit

Format your code to look like this. Separate the part that handles data from the part that applies the data to the world. And stop plugging multiple flows into a single input

quick imp
#

Alright so it applies the Itemnumber and all the weapon customization variables, then sends a local custom event to apply and se tthe gun active

#

(The other end of the chain of customization appliers)

wary summit
#

yeah that's it, that's the general structure that makes networking easy

quick imp
#

Well I guess Il have to open parsec and see if it works ๐Ÿ˜›

wary summit
#

what, like in order to run multiple clients? VRChat has tools to do that built in, you can launch multiple local test clients at once and it goes through the relay servers so it's fairly representative of how networking is gonna work in the real world

quick imp
#

Oh? last I checked it threw an error when I try offline testing or something

#

So yeah I just used multiple accounts to test stuff

#

I kinda figured it was a legacy feature or something

#

Also this, this is new to me

visual cargo
#

well it's what it says on the tin

#

you have VRCObjectSync on an object that has another UdonBehavior, and that other behavior is using manual sync

#

ObjectSync needs continous and you cant have mixed sync types on the same object

quick imp
#

Well damn, how am I gunna make a gun move with a networked player if I cant sync it?

wary summit
#

put the manual sync udonbehaviour on a separate child object of the pickup

quick imp
#

Oh... I see, that might need some work

quick imp
#

I think it was post the anti cheat update

visual cargo
#

oh that's why

#

you are targeting the wrong launcher

#

in the SDK, in the Settings tab, check what path is here

#

I think it does the EAC problem if you're targeting "launch.exe" instead of "VRChat.exe"

quick imp
#

Oh I see, I assume that disallows any activity outside of your test world, so you cant play the normal game after testing

visual cargo
#

it's EAC that blocks it. You can't have more than one game running EAC at the same time (for example you can't launch Elden Ring and VRChat at the same time)

#

but local testing ignores EAC

quick imp
#

Oh I didnt know that seperate games under it were affected

quick imp
visual cargo
#

no

#

hence why it's called local testing

quick imp
#

Figured, that would have been a pretty hilarious oversight if so lol

visual cargo
#

though I've been having a kind of related issue recently. If I run 1 or 2 local clients it's fine, but for my world I need up to 6 clients, and usually about half of the clients get a popup saying "You're in a local test and cannot join public worlds" yadda yadda, even though I never attempt to leave the world, it's just a few seconds after joining the local instance. Then a bit later those clients get another popup saying "Unusual client behavior", then it boots those clients to the error world

quick imp
#

Ooof

#

Not so easy anti cheat

visual cargo
#

it's not anticheat doing it

#

or else I wouldn't be able to launch 6 clients in the first place

#

VRChat is confused about somethin and I haven't investigated what

#

I use the VRC Quick Launcher in the "Tools" tab of the VCC btw. It's awesome, automatically opens whatever howmany clients you want when you build, then automatically moves all the windows where you can see all of them at once

quick imp
#

Oh i see

visual cargo
#

โ—‘๏นโ—

quick imp
#

How you controling 6 players with only 4 limbs

#

I mean on a good day I might be able to use my tongue to control the 5th but 6! you madman

visual cargo
#

I'm very dexterous

#

and I'm pretty good at mashing alt+tab

quick imp
#

Remembers episode 1 of no game no life anime

visual cargo
#

I thought it was possibly my code doing it but this is a practically empty testing world, not my main thing, and the same thing happens

lusty lion
#

Can anyone tell me what I'm doing wrong here?
I'm trying to make a object activate when I interact with a cube. In offline test everything works fine but when I upload to my world the cube I need to interact don't show up and I don't know why. Can anyone help pls?

visual cargo
#

the ACTION section looks a bit odd....

#

Interact starts that block. easy enough.
Then I'm going to assume "LocalPlayerHasBeenRestored" is true and it will continue to the next block.
In that block, you check if the object "botao" is active, and if it is, continue.
This means that if this object is disabled, the Branch will never continue and activate the object
Which seems a little odd. Why check if something is active, and only activate it if it's already active?

#

did you mean to do some UnaryNegation and toggle the object on and off?

junior goblet
#

Is OnPlayerRestored called when that object / owner's data specifically is restored or should you be checking against the player who's data is being restored && the current playerobject's owner?

visual cargo
#

yes it's for every specific player, OnPlayerRestored provides you the player whose data is being restored

lusty lion
#

But for some reason in offline the button to interact shows up and when I upload to my world it doesn't

visual cargo
#

the button itself is gone?

#

so something else is disabling it

lusty lion
#

This is the rest of the code
idk if this will help

twilit meteor
#

is it because of the data you are loading?

#

I can't read graphs ๐Ÿ˜ตโ€๐Ÿ’ซ
But it seems like when your data is loaded, you set the active of object?

Is the object the button?

visual cargo
#

is "botao" the button?

lusty lion
visual cargo
#

if the button itself it separate and not referenced in the script then it won't be this script that's causing it to disappear

#

is this a PlayerObject?

lusty lion
visual cargo
#

and you assigned "botao" to a GameObject in the Inspector? I believe it will be "Self" if nothing is entered

lusty lion
visual cargo
#

huh.... something else has to be disabling it

#

what if you put the script on a second GameObject

lusty lion
#

I was making the button the botao

#

So I tried to add another object to be the botao

#

In offline it looks like this

#

When I upload it look like this

#

The left object is the button

visual cargo
#

oh so the button is there

#

it's not the one disappearing

#

it's the botao

lusty lion
twilit meteor
#

Yes...

visual cargo
#

that's what I was going to suggest

twilit meteor
#

Your reading your data and you have no data

#

So the object is toggled off

visual cargo
#

ClientSim + Local Testing + Live can all have different persistent data

#

if I'm reading right, you load the key JumpDataKey, which loads to false by default if it doesn't exist

#

so when a player joins for the first time without any prior data, it will immediately disable the object once they load in

#

and I don't currently see a way where the bool will be set to true

#

but your past code may have set it true, so persistently it would sometimes load in

lusty lion
visual cargo
#

welp that would do it lol

visual cargo
#

if you try to load a key with the wrong type, it will also give it the default value (false for bools)

lusty lion
#

Like what would be the right type for bools?

twilit meteor
#
#

familiarize yourself with types

visual cargo
#

what do you mean what would be the right type for bools?

twilit meteor
#

Bools are just a type of a data
0 or 1

visual cargo
#

bools is a type

twilit meteor
#

true or false

#

I would slow down a bit on whatever your doing and figure some of the basics out or your gunna be banging your head against a wall

lusty lion
twilit meteor
#

well that can be whatever you want

#

think about datakeys like a variable

#

that you can access and modify

#

the string if just how you refer to it

lusty lion
#

The update part set the gameobject off and I forced to make it set activate and now he shows the botao

dense owl
#

Probably not a persistance specific question but it started happening when I implemented PlayerObjects:
What usually causes players to be sent to the void as soon as they join a world?
It keep happening when there's 3 players or more in a world I'm working on, but I have nothing (that I remember of) checking for specific number of players. (and even so it should only be the related graph that crashes, right? this problem probably is something more worrying to fix...)

#

Also just to confirm, when a PlayerObject gets "turned off" in the hierarchy after a test build that means there's a problem in it, right?

viral linden
#

PlayerObject tuned off is normal, the original is a template that gets copied, but the template itself is always off

dense owl
#

a spawn point problem?

#

player spawn correctly alone or with a second player, not falling throught the ground or anything

#

I have a checkpoint system, but it should only TP after "OnPlayerRestored" tho...

twilit meteor
#

OnPlayerRestored is called for every user whenever someone joins

#

So I imagine it could be related to that

dense owl
#

I guess since it's a world focused on persistant experiments that's...a lot of objects relying on that ye...

#

especially since I got lazy with the minimap system, just putting a "if player enter the trigger, turn a bool true and the object off. onplayerrestored if bool is true automate same action" on the tile (not a playerobject) instead of having a manager array. That's probably A LOT of new objects checking who have unlocked which part of the map.

#

Oh well, time to make a manager to alleviate a bit of that

twilit meteor
#

It can get squirrelly real quick

dense owl
#

Ok yeah, even that small test section was already 75 tiles. That adds up super fast

#

Now it's just one manager running a "For"

dense owl
#

Ok I am confused as heck now...
Finally was able to test out the manager (something at home caused some AFK hence the delay) and now only the 1st player isn't stuck in a loop...

#

still weird that it works with 1 or 2 players but not starting 3. I don't even know what to ask if I go to the networking channel

twilit meteor
#

You probably gotta drop some code

dense owl
#

if I even knew which graph to look at that is

visual cargo
#

hopefully you can tell where in your own code networking stuff is being done

#

if it works for 1 person, but starts failing when more are being added, then the networking is probably getting goofed somewhere

dense owl
#

it works for one

#

and works for 2

#

starting 3 it act weird

#

Also I'd really need to learn when it's safe for UdonBehaviors to be set as "none" someday...

#

because the console don't tell me anything...I corrected all it asked to each time I work on something

visual cargo
#

which means you have a logic error

dense owl
#

but feels like that's...a lot of IDs

visual cargo
#

actually yeah that is a lot of IDs....

#

do you have a lot of objects with Udon scripts on it or lots of pickups?

dense owl
#

a good chunk of them probably are from the pixelcanvas... ^^"

#

a ton of Udon ye

#

not that many pickups

#

but most of them are generic event senders. "if interact, send "event name" to "target udonbehavior"

#

it's mostly the target (managers) that do the heavy lifting and loop a lot

#

but the 3rd player thing only happened recentely and I corrected the game mechanic that had lot of UdonBehaviors for it (the persistant fog of war on the minimap)

#

Now a logic error wouldn't surprise me, i barely knows what I'm doing with these graphs

#

How do people usually rule out these kind of things?

visual cargo
#

a looooootta debugging

dense owl
#

yeah no that much is obvious xD

#

was more asking about what method to follow to even find what would cause it

#

I don't know where to start

#

can't think of anything aside of "remove stuff from the scene till it stop breaking

visual cargo
#

that is sort of a method

#

but with many interconnecting scripts it might just not work at all doing that strat

dense owl
#

ye, plus if I mess up it's destructive

visual cargo
#

you just have to systematically narrow down where the issue could be

#

I would currently be thinking, it has to be something network related.... so I'd go through and reread, go through the execution in my head and figure out where anything could possibly go wrong

#

and when it comes to networking I usually just enable printing out the OnPostSerialization result stuff and just make sure it's actually successful \

dense owl
#

considering there's an idle game with auto-click feature AND the playertracker for the minimap...that's the two things that would fire the most time

visual cargo
#

then next I usually check "am I using/updating variables at the right time" which usually involves me printing out the variables on Update to a TextMeshPro, so that I always see the current value, and see if anything obvious is happening wrong with that

dense owl
#

but idle existed since the very start of the map so it worked fine

visual cargo
#

oh yeah and with so many things going on, maybe something is hitting limits

dense owl
#

yeah I mean...I don't even know how the world even work at all

visual cargo
#

could be 1 person it's fine, 2 people doesn't reach it, but with 3 limits start getting reached

dense owl
#

there's the idle game, the respawning nodes for making the house, the minimap, puzzles...the pixelcanvas that itself is already 32x32 resolution

#

that's...a lot

#

to be fair the scope of the map was "work on it till you find a limit" but it's sad if I reach it at the minimap... xD

#

"we can finally make exploring interesting, also we can't add anything more"

visual cargo
#

a minimap may not need any networking

dense owl
#

nah it's just the "fog of war" that's persistant, but everything is run locally

#

but that adds a lot of individual bools to check which tiles you unlocked (only happen once, on PlayerRestored, but like you said earlier that fire for every players each time, with how many things are persistant in the world that's...a lot)

#

75 for the small test area

#

Like, can be completed in a minute" small...

#

(in a normal world I'd probably make the tiles really big, here was just to feel like you unlock as you walk)

visual cargo
#

hm but wait what part was failing? Loading this "fog of war" persistently, or things syncing between players?

dense owl
#

It doesn't fail. It's PlayerData and check LocalPlayer's keys (each player unlock the map on their own. 1 tile = 1 bool)
I just said it still relies on OnPlayerRestored for loading the states and that's a lot of keys being called
Since there's all the other persistant systems too.

#

that's why I'm so confused about the potential logic error, because everything works when alone or a 2nd player (like you said I'm probably hitting limits of something)

#

The easiest way to understand how much is going on would be to visit the world, honestly ^^"

visual cargo
#

The Cube Game?

#

dios mio

dense owl
#

yeaaah...

#

I updated the description so people know there's a problem.
Also you don't see much at the start, there's a whole house to build and the underground labyrinth is way bigger than the new one made for the map system...but you need something from the house to unlock the entrance

visual cargo
#

well I've rejoined the world and it seems some fields have default values rather than being loaded

#

there's another person in the instance with me

dense owl
#

interesting, this one didn't used to break

visual cargo
#

this too

#

so how exactly does this maze minimap break with more people?

dense owl
#

it's not the maze, it's the whole world

#

when there's 3+ some players get stuck in a loop of rejoining

#

or sent back to their home world

visual cargo
#

ah ok

dense owl
#

as said before 1 or 2 players seems to work fine

#

but 3+ is a hot mess

#

The score tracker (not really a leaderboard, order is by who joins first) I know it breaks when people leave and someone else rejoins

#

so at least this one can be explained

#

local test 2 cliens. Works at first, freeze for the player when the other rejoins (break completely on the rejoining player's side)

#

just me not handeling players IDs correctly I guess

#

but I'm still new to networking

twilit meteor
#

The leaderboard prefab has the ordering setup. IDK if you have taken a peak at that

dense owl
#

nope, whole world was just me taking shots in the dark (especially the very early stuff like this)

#

I'll go look at it

twilit meteor
#

๐Ÿซก If that is the case, I would revisit all your code. Especially as you improve

dense owl
#

I'm sure a lot of things breaking are because of bad PlayerID

#

like...100% sure at this point xD

visual cargo
#

it's hard to single out because this world has so much in it

#

I get a couple of scripts crashing when the third player joins

twilit meteor
#

I would go clean slate and make sure your systems are working 1 by 1

dense owl
twilit meteor
dense owl
#

there's also older systems (like the house and nodes) that are just stuff made compatible with persistance

#

but that were from when I was even worse at UdonGraph than now

#

the world is a hot mess xD

twilit meteor
#

I can relate w/ that one. My older features are very obvious that I had just learned how to do them ๐Ÿ’€

dense owl
#

and it's nothing compared to how much I crammed in the on-persistant test world I had before...

visual cargo
#

the most I can parse is there's a handful of things trying to reference nulls..... and errors of the persistence keys being invalid

dense owl
#

(a portal to it is actually the reward for the idle game, since it's still private, but I could guide you)

dense owl
#

since I changed the map from stand alone tiles to a manager

#

but that should only be if you already had a save...unless I finally hit the limit

#

I know it's probably that because it's a new error from when I updated it

#

now the nulls I don't know (aside of invalid PlayerID for stuff like the score board)

twilit meteor
#

get to searchin

dense owl
#

yup

#

I fear that will be all I'd do for the next days xD

visual cargo
#

I'm trying to parse the raw hex dump of the errors...... but my guess (emphasis guess) is that when you're loading persistent data, the VRCPlayerApi is invalid, causing a cascade of values to be null references; I see the null failures on getting the player's display name (string), three bools, and an int or two

dense owl
#

But yeah blank slate and making everything their own cleaned up prefabs seems like a good thing to do

visual cargo
#

why this happens with 3 people, no idea

#

yeah if this is a practice "scratch" world, it's an option to go "welp I learned a lot from this but it's too broken beyond repair" and start anew

dense owl
#

yeah

visual cargo
#

the systems you actually want to use, port to a world by itself and start debugging then

dense owl
#

or to apply the relevent stuff to worlds that are actually reasonable in scope

#

ye

#

this world is basically brainstorming visualised

visual cargo
#

I was gonna say earlier that I feel like I'm just walking around inside a mad scientist's notebook in this world

dense owl
#

that's pretty much spot on with the notes written on the walls... xD

#

if you want to have some fun looking at the other world I could give you a hint to skipping the grind

#

that's the least i can do to thank you for trying to help

#

||It's actually hinted at in the wall where I say hello to the player, but there is something related to holding a mirror. One is unlockable with the idle game, but your player mirror works too. There are things written on another wall only mirror can reflect, the next step is beyond said wall||

#

I would join to show but I feel like that'd be 3 players in world right now... xD

visual cargo
#

these doohickeys?

dense owl
#

||ye, just try to reach what you see, they have collision||

#

||the text itself is just references to memes from friends||

#

also wait...the wall don't show ||on the mirro||r now...?

#

uh...why did I changed it again, there should be a reason...

#

oh right, because the underground labyrinth's points at this from under as a hint if you missed it

dense owl
dense owl
#

(ok I found the "invalid keys" it's because the non saved tiles were still in the array...silly me)

dense owl
#

Oh...

#

Yeah no that's a loooooooooooooooooooooooooooot of calls for PixelCanvas to initialize...
(and worse than what the image suggest when you realise how much it has scrolled down)

#

Ok I must rethink the logic but again...that means this many objects to manually link in the array if I make a manager

#

Working in graphs is such a pain for stuff like that...
(unless there's a way to mass dump references from hierarchy to an array but I never found it...)

#

@visual cargo I guess this would be my best bet if I had to only nuke one asset to test if things go back to normal.
Or just removing the alt resolutions and see if the world works for 4-6 people then break again (aka: limit is pushed back but not solved).

dense owl
#

ok, instantly 3 players works again, it was the PlayerObject

#

4 still breaks but removing only x8 and x16 isn't much (from 2.3k to 1.9k) so it's expected

#

x16 alone is almost under 900, so theorically I can double the number of players...?

#

ok let's NOT local test 8 players again...the clients went "unusual behavior" error... xD

#

guess I'll have to stress-test live

dense owl
#

after 8+ hours redesigning the thing...I'm back to square one

#

I really need to introduce a custom delay, even without using OnPlayerRestored it keeps breaking the world at 3 players

#

without save it runs fine at 3+ even tho all the tiles still initialize to make the canvas white tho...

#

it's really just...something caused by persistance in the PlayerObject

#

It's so weird because the "update material" thing runs a networked(all) custom event so it should be as heavy but no, it's only when I introduce loading persisted data into it that the world breaks...

#

guess I'll really have to bit the bullet and asign all the tiles one by one in the inspector to run an array with the custom delay...so much pain for such a gimmick asset.

visual cargo
#

fyi you can multiselect GameObjects and drag them into an array all at once, instead of dragging in each and every one individually

#

or you can do a weird thing I did before; have the tiles add themselves to the array, by calling a function that automatically expands the array and puts itself in

dense owl
#

do I need two hierachy open or something..?

visual cargo
#

you have the object with the behavior selected first, then click the lock icon on the top right to keep it open

dense owl
#

there's a...

visual cargo
#

ever notice this doohickey?

#

very tiny and very easy to miss

#

I didn't know about it until a friend told me

dense owl
#

oh ffs it could have saved me months at this point of always going 1 by 1 on every thing I made over the past 4 years...

visual cargo
#

I had the exact same reaction

dense owl
#

especially the book system and whatnot

#

Well if it really works I should be done in uh...just the time to relink together the custom delay from before and dragging the thing I guess

visual cargo
#

imagine dragging in 110 GameObjects one by one

dense owl
#

how do..uh...

#

I'm confused...

#

the interface is different

#

also just tried it only put the 1st one in the 1st cell...

visual cargo
#

what about the interface is different? (I moved the hierachy right next to the Inspector so I could take a video of it easier)

dense owl
visual cargo
#

did you see where I dragged it in

dense owl
#

I should maybe have mentionned I'm a graph user...

visual cargo
#

oh it would be a real shame if this didn't work for graph....

dense owl
#

yes, but in the number here just give me a block sign, won't allow me to drop at size

#

only in the cells

visual cargo
#

can you drag it to the empty space next to "Tiles"

#

not into a cell

dense owl
visual cargo
#

uh oh!

dense owl
#

the cursor just becomes this

#

unless it's in a cell

#

yeah...guess it's U# exclusive...

#

yes, I did, it gives me vrcStop everywhere I hover, except for the cells

visual cargo
#

oh yeah it don't work....

#

that's gotta hurt

dense owl
#

especially for a 32x32 canvas

visual cargo
#

could make a dummy U# script purely to hold the array lol

dense owl
#

I...guess

#

how do you access U# scripts from a graph again?

#

you can't just drag the Ubehavior like for a graph to another

visual cargo
#

you make a public UdonBehavior variable, put the U# script on a GameObject, then drag the GameObject into the variable

dense owl
#

oh the game object directly, gotcha

visual cargo
#

might actually be a viable option for the plan B I described

#

program variables can get arrays right?

dense owl
#

if it's the same as in graphs ye, int and int[] both exists for example

#

actually It's probably better if I do two arrays (one listing the tiles and one for the color assigned) so it only need to run one object checking which tile was interacted with instead of all tiles checking if the pen touched them

visual cargo
#

ok so ideally you make a U# script that lierally all it does is public GameObject[] myObjects;, then it'll appear in the inspector
Then in your graph, at Start assign your array to the other array

dense owl
#

at start? Oh right...I totally forgot you need a dummy/math array to modify one on another behavior...

#

well I just need to match the length anyway

#

the rest I already did in the past

visual cargo
#

yeah it'll probably be easier to just copy the dummy, rather than change your entire graph to keep referencing the other array

dense owl
#

yeah usually I go
A[] = B []
Make changes to specific indexed of A[]
B[] = A[]

#

because sending change on only specific indexes act super weird but full array A = array B seems to work consistantly.

visual cargo
#

ah like networking changes to arrays?

dense owl
#

between graphs ye

#

like here let say the pen touch "tile 404", only the color value of index 404 on the reference/dummy should change

#

but it just act weird when it communicate between graphs trying to do that

#

sending the whole array works fine

#

so I just do the calculations internally with a math dummy

visual cargo
#

it probably didn't work because OnVariableChanged doesn't fire when you change array contents, only when you change the entire array

dense owl
#

ye

visual cargo
#

because, technically, the array never changed

dense owl
#

it's not a hard workaround so it's fine

#

but thanks for the reminder

#

uh...I guess I should had asked how to create a script first...

visual cargo
#

rut roh

dense owl
#

I swear the pain of working on this is reaching cartoon levels xD

#

at this point I'm better off comissioning someone who knows what they're doing xD

#

guess I should had specified more often I'm not a programmer ๐Ÿธ

visual cargo
#

you are a programmer

#

you program with graph

dense owl
#

ok let me rephrase it as coder then

#

took me 3 attempts to make a script, now saying it's invalid (but at least Unity stopped crashing

visual cargo
#

you went to Create > U# Script to make it right?

dense owl
#

compilation validation failed, just by creating the script ._.

#

ye

visual cargo
#

that's really funny

dense owl
#

and then create when it says it misses one

visual cargo
#

should make two files that look something like this

dense owl
#

yes that's what I did, and it throws me this error

visual cargo
#

what does the console say

dense owl
#

source is null

twilit meteor
#

it bugged when u made it or something

visual cargo
#

their names have to match exactly

#

one of them has a different name

dense owl
visual cargo
#

das weird

#

delete and remake them

twilit meteor
#

Just delete it and remake it

#

it happens to me sometimes

dense owl
#

I swear this engine is just messing with me at this point xD

visual cargo
#

sometimes it's out to get you

#

have you recently said aloud that a certain game was bad, and that game was made in Unity?

#

Unity tends to hold grudges

dense owl
#

I don't even have time to play games

#

spent the last 8h trying to debug this thing

#

and that's jsut today

#

that canvas alone is ruining the world I'm this close to just delete it and pretend it never existed xD

#

I understand why Prismic answered they have no intention to work on a similar thing when I asked if it's ok for me to try making one (asked since it's similar to their VRcanvas world)
...Yeah no, don't touch this can of wasps even with a long stick xD

#

oh

#

it's create -> U# script

#

not the VRchat dropdown...

visual cargo
#

yea that's what I said earlier

#

lol

dense owl
#

no wonder it didn't worked!

#

sorry I missread cause I'm tired and assumed the VRchat thing was...in the VRchat dropdown

#

silly me

#

a VRchat thing in the VRchat category what was I thinking xD

#

well at least it's becoming silly enough to give me a good (nervous) laugh

twilit meteor
#

console

visual cargo
#

Compile again after you deleted the old script

#

Compile All UdonSharp Programs

dense owl
dense owl
visual cargo
#

and deleted the old two files?

dense owl
#

yes

visual cargo
#

it's not happy with NEW.cs

dense owl
#

which was created following the instructions ._.

#

at this point it's maybe healthier that I take a break

#

I mean the only break I took was to make food

twilit meteor
#

Take a break. ๐Ÿซก

dense owl
#

also I know it's just skill issue on my part

#

only time I ever used U# was to mess with an existing script by shifting a value

twilit meteor
#

I had a similar experience when I started U# vs Graph

dense owl
#

I kinda wish the QoL was just the same for the inspector...Like this whole shenanigan started because you can mass-drop in one and not the other...

visual cargo
#

we can only hope Soba has it

dense owl
#

and the problem before it because persistance in PlayerObject seems to behave like OnPlayerRestored even if you don't use it so the network still get saturated...

#

even with me trying to introduce a delay to load tiles one by one

twilit meteor
#

How big is the data you are saving and loading?

dense owl
#

like I don't care if my prefab takes 10sec to load as long as nobody freaking crashes...

dense owl
#

32x32 tiles and 24 possible colors

#

So, 32x32 (1024) length array of int 0-23 basially?

#

I mean righ now it's just stand alone tiles having one variable stored inside

#

but that means a shitton of calls on loading the persistant data

twilit meteor
#

and every user is loading everyone elses data?

dense owl
#

hence me trying to use a manager and array instead

#

so at least it only load one object per player

#

but 1k+ objects to drag manually, it's killing me

#

yet I lost a full day

#

at this point it would had been faster to just do it

#

but I don't even know if it would do anything because it's my first PlayerObject

#

it's been a nightmare to work with compared to PlayerData

#

I've made a fog of war that unlocks as you walk in the tiles in like...An hour or two with PlayerData

#

and it's practically the same except instead of a bool it's an int since there's more possibility with colors

#

and you collide a pen not the player

#

I don't want to make the canvas a PlayerData thing because it makes sense to instantiate them

#

and I want to use some of the PlayerObject data to not burn all the PlayerData one...

#

if it was the only asset in the world honestly I'd make a PlayerData version

#

but the whole point is to learn both sides of persistance

twilit meteor
#

I was gunna say, I think this would be cheeze w/ playerdata

dense owl
#

yeah no with Pdata? piece of cake

twilit meteor
#

So you want a PObject w/ their persisted data basically

dense owl
#

even the fact you don't have to reference other objects to retrieve the data it's SO GOOD!

#

like, Pdata is really good, I had a blast working on it since the public beta dropped

#

Pobject on the other hand had been a nightmare non-stop to work with

twilit meteor
#

This could be the case of trying to use one thing when the other version is far easier

#

like ur overengineering it

dense owl
#

well eah but the whole world uses Pdata so I fear of running out of data if I make a wholeass canvas...

#

the point of using both sides is also to allow the prefab to exist in an environment where the other side's data mays already be taken

visual cargo
#

the thing about PlayerObjects is, they're practically the same as the networking that already existed

#

and you don't really need ot reference other objects to get PlayerObjects, they're linked to the player, you can get it from them

dense owl
#

it's a bit on pupose that I use all the PlayerObject data on one thing (max resolution before it beaks without kicking a single player is 58x58 so I still scale down safely)

dense owl
#

hence me deciding to redesign it using two arrays on one object

#

but graph is a pain having to drag manually

visual cargo
#

which seems odd..... it should only be loading about 4096 bytes per player? usually even smaller due to being compressed

dense owl
#

my guess is it's less the ammount of data

#

like said max for 1 player is 58x58 resolution

#

not kicking them, just reaching data limit

#

and I scaled down a lot

#

so it's more the number of calls on same frame

#

loading the one variable on all the tiles

visual cargo
#

that's still way smaller than it should be able to load

#

hmm

dense owl
#

did you factor in the number of colors? they're not bools

visual cargo
#

yes they're ints

dense owl
#

ye

#

but yeah i'm not nearly close enough to the data limit in term of size

#

probably the calls that flag as spam

#

because if I let it run enough I get "failed to authenticate" and can't even connect on normal VRchat for like an hour xD

twilit meteor
#

Something doesn't seem right..

visual cargo
#

so with your max resolution, each player is storing 13,456 bytes raw
in my testing players could store up to 300,000 bytes with no issues

dense owl
#

when I close the localtesting clients and it reaches the number of players where it is known to not crash tho, the one in a loop loads correctly

visual cargo
#

I'm gonna modify my PlayerObject tests to mimic your amount of data

dense owl
#

I mean I could send you the prefab xD

visual cargo
#

your graphs scare me

dense owl
#

as they should xD

#

I don't count how many times I had to separate some because i hit the limit of nodes...

twilit meteor
#

Gotta learn U# brutha

dense owl
#

like the "persistant skill tree" it have one manager then one graph per thing you upgrade

dense owl
twilit meteor
#

Nah graphs just get outta hand w/ anything complex

visual cargo
#

I think when it comes to processing lots of data in even semi-complex ways, graphs just explode

twilit meteor
#

I cannot fathom trying to do what ur doin in graph

dense owl
#

xD

twilit meteor
#

Like in U#, sounds easy enough

dense owl
#

the scale is big but the pixelcanvas itself is simple compared to everything else in the world tho...

#

literally just triggers that change one variable when the pen touch (copying the pen's current color) and assign a sharedmaterial off the reference array

#

and the pen changing its own when colliding with the palette's objects

#

like...that's it

#

then just save the tile's int value, run the "update material" on load

#

and yeah that's literally it

twilit meteor
#

Yeah this doesn't sound too bad in U#

dense owl
#

I'm sure someone in U# could remake it in an hour

#

the objects themselves are just cubes

#

or quads

twilit meteor
#

I wouldn't have done colors tho without just getting a basic bool for the tiles that are changed

dense owl
#

quads seems more appropriate here

twilit meteor
#

Like if I were you
I would have made sure I can load 32x32 worth of bools for each player

dense owl
#

the pen have the array of colors for its own collision, the tiles check the pen's array so the indexes for a wanted result always matches

dense owl
#

so in this context it was "pretty safe" to assume that scaling down to 32x32 would be fine

#

since 58x58 was fine

#

(not bools, literally same canvas with stand alone tiles)

twilit meteor
#

Nah what I mean is like being able to load the data w/out a hitch.

#

Cause something you got going on isn't working right.

dense owl
#

it worked fine with 1 player...you know how many people I get to answer my invites even when there's 60+ firends online? Zero ๐Ÿคฃ

#

so stress-testing was uh...I tried

#

I AFK'd in the world all the time

twilit meteor
#

Make an alt and use the quick launcher

#

and always test w/ the quick launcher with multipel clients

visual cargo
#

launching 6 clients rn to test

dense owl
#

since the problem start at 3 players I wouldn't had seen it even with one alt

#

maybe for the 58x58 yeah 2 would had triggered

#

for context on how long I AFK'd trying to test stuff live in that world (since the last time i had to wipe my data)

#

(synergy hits once every 10 seconds)

#

jokes aside yeah I get so few responses it's probably better if I start making alts

visual cargo
#

naur just use the client launching tool lol

#

even tho I still have issues with it....

#

so I successfully, persistently load an int array of size 3364, totaling 13520 bytes when serialized

#

this gets compressed down to 6878 bytes

#

takes about 1 second to sync

dense owl
#

I'm aifraid to send you the package...

visual cargo
#

hit me

dense owl
#

knowing how my graphs works on luck and hopes we can take bets on something looping or whatnot... xD

#

rather than real problems

#

ok I'll send the V2 in DMs, since it was the last stable version of the prefab before today's rework

#

oh ffs I try to put it in the scene to test if nothing broke and Unity refuses to build now

#

ok what graph that V3 also uses conflict now...

visual cargo
#

It's just UdonSharp that failed to compile

#

and you've only got the one U# script no?

dense owl
#

OH

#

right

#

I created that thing earlier...

#

forgot it existed...

#

ok it builds now...thanks for the reminder again

#

guess I'm really earning this "mad scientist" nickname you gave me when you 1st visited the world...

velvet barn
# dense owl I understand why Prismic answered they have no intention to work on a similar th...

To be clear I didn't say I had no intention to lol, just that I had no plans for it currently (which is still the case). The concept has been in my notepad of potential world ideas, I just don't have any present drive to make it, and when you expressed interest in your own version of it, all the less reason to want to spoil that ๐Ÿ™‚ In fairness to you as well, doing it in graph does sound like a pain ๐Ÿ˜“

dense owl
#

yeah I worded it badly, it's true that the focus was "at the moment"

#

but man this is giving me such a bad time at this point it's healthier to wait for whenever you'd make it the correct way xD

#

also the thing totally works and saves, the prefab itself was finished like, weeks ago

#

it's just this networking issue that's literally world breaking

velvet barn
dense owl
#

sending players in a loop of rejoining, back home or worst case scenario "fail to authenticate" timeout

velvet barn
dense owl
#

learning how networking works instead of taking shots in the dark may help ye... xD

#

I don't want to make it local/PlayerData tho, the world already uses a lot of persisted objects

#

the whole point was that PlayerObject is instentiated so players can see everyone working on their canvases

#

(they spawn with an offset using the player's ID to not overlap)

#

and a dummy "player have left" canvas replace the PlayerObject when someone leaves

#

(unfortunately just a dummy, never found how to duplicate the canvas content on player leaving)

#

but yeah solo you can already try it in the world

twilit meteor
#

I'd suggest taking a look at the leaderboard prefab in the example central

dense owl
twilit meteor
#

It's in U# too ๐Ÿ˜

dense owl
#

oh boi...

#

I mean reading a script isn't too much of a problem

#

my brain just freeze when I have to write in a "list" format like coding

twilit meteor
#

I think you'll manage ๐Ÿซก

#

Feel free to ask for help, I am more familiar with U# over graph

dense owl
#

Even when I was designing for ProjectAincrad that always was a problem that I had to use Canvases in Obsidian instead of writing notes...it's beyond just learning to code

twilit meteor
#

Graph makes me wanna gouge my eyes out

visual cargo
#

I think something like this would need a proper execution outline, a plan, rather than creating it flying by the seat of your pants

#

a design of a data structure optimized to work for a painting canvas would be ideal

dense owl
#

yeah I mean, the PixelCanvas bug was unexpected, the thing itself works "fine enough"

visual cargo
#

doesn't really help that graph doesn't give as useful of errors

dense owl
#

but yeah these tiles can't be stand-alone that's for sure

visual cargo
#

U# will tell you the exact line and column an error occurs

dense owl
#

are there many other errors in it aside of players vanishing to the shadow realm? (since you're looking at the package I sent)

visual cargo
#

just one, a bool being angry

dense owl
#

a bool...

#

I don't use many in this one, check the resolution buttons

#

for the generic object switcher

#

OH, or it's the canvas reset button, right I never finished that one on the old version

visual cargo
#

ah I found it

dense owl
#

since it needed the bigass array xD

visual cargo
#

Target_Switch array in the ObjectSwitcher_V3 script on Resolution8x8, the array has no GameObject in it

#

script crashes attempting to access it

dense owl
#

yup, you didn't put the dummy in it like I said in DMs xD

#

I always have a dummy empty for stuff like that in my projects (probably a bad habit)

#

they crash all the time when there's an unused part...

visual cargo
#

probably better to check if it's null first and then handle it lol

#

I usually check for it, then output to the console telling myself I forgot to assign something

dense owl
#

believe me in graph? always put a dummy, you never know when something crashes just because why not

#

always fill all the fields

visual cargo
#

same thing will technically happen in U#

#

you can check if an object is null and ignore it or whatever, instead of letting it crash

dense owl
#

that sounds useful. dunno if there' a proper way to do the same in graph

#

I just put flex tape where things break and hope for the best

#

dunno how the co-op puzzles in that world don't break when I'm so bad with networking xD

visual cargo
#

interesting.... canvases handle ClientSim remote players just fine, can get over 3

dense owl
#

ah right, I usually just build&test ._.

#

I mean, the limit may be higher on your end since you don't have the rest of the world running

#

remember that I have the idle game and whatnot (even tho they're local, the score is just fetched once a second for the leaderboard)

visual cargo
#

I managed to get to 4 players

dense owl
#

does it still break at 5+?

visual cargo
#

as the fourth player joins, they get stuck in a loop

#

now have what looks like more meaningful logs

dense owl
#

ok being stuck in a loop of rejoining is what happened ye

visual cargo
#

soooo this looks like where Network.IsNetworkSettled becomes useful

dense owl
#

"you're doing it too quickly" ye we already figured that was the problem... xD

#

but yeah no wonder it just timeout the player after that rapid fire of warnings

visual cargo
#

when a player joins, they load the data for all PlayerObjects in the instance; it seems when it gets to around 3-5 or more, it becomes too many requests too quickly, but we never stop to wait, it just keeps requesting over and over until VRChat just thinks there's a problem and restarts

#

and now we have this lovely infinitely-growing wall of dead canvases

dense owl
#

yeah

#

well at least the problem is successfully replicated

#

I would want to know how to slow down, that's what I tired to do the whole day today

#

I got rid of OnPlayerRestored to introduce a SendCustomEvent(delayed) with a random range

#

because I don't care the other the tiles appears, just that they don't fire at the same time

#

but even calling this one would mean they all call it at some point

#

so, it's the snake bitting it tail

visual cargo
#

I think you'll still want OnPlayerRestored, but also use IsNetworkSettled to further determine if the data is ready to use

dense owl
#

never heard of that one ._.

visual cargo
#

something gets caught in the loop trying to use data when it isn't ready yet

dense owl
#
IsClogged    Returns true if there is too much data trying to get out. You can use this to wait until the network is unclogged or to adjust your logic.

wouldn't that one also be useful?

visual cargo
#

that's outbound data; our issue is inbound data, when a player is joining and attempting to download the data

dense owl
#

ok

visual cargo
#

still might be good to add. It's another thing to wait for to really make sure everything is ready to use

#

So OnPlayerRestored -> Is NetworkSettled? -> yes? then IsClogged? > yes? now start using data

#

if either is no, wait like 2 seconds and check again

dense owl
#

uh shouldn't clogged be no? xD

visual cargo
#

er yeah lol

#

curse bools

#

I always try to make bools where true is the "continue" condition, but IsClogged is flipped

#

should be IsNotClogged imo

dense owl
#

like that?

#

I keep the range so they don't just all fire as soon as things are ok or it will instantly clog again

visual cargo
#

That works, except I'd just do OnPlayerRestored > call Check network Ok, then put Check_NetoworkOK where OnPlayerRestored currently is

#

Merging noodles can cause the compiler to freak out sometimes

dense owl
#

for comparison that was what I made earlier today... xD

#

since I assumed OnPlayerRestored is when it's safe to load data, as it's how it was made look like when I was learning

#

but yeah extra checks don't hurt

#

Problem was that Start and OnPlayerRestored would still fire at the same moment for everyone, rendering the delays that comes after useless (hence my back to square 1 when I started to write here)

#

I should probably add a "is initialized" bool as killswitch for this loop...just as a failsafe right?

#

...

#

as expected from OnPlayerRestored fireing at the same moment before the other checks occurs, player 3 still bugs

#

which make sense since everyone is trying to run OnPlayerRestored BEFORE asking the other questions

#

and will try to run it regardless if it is used anyway...since it comes before the checks

#

I guess same would apply even to Start...

#

I really see no solution aside of using the "array in a manager" method instead of stand alone at this point

#

even if there was an equivalent of NetworkSettled" as "OnSomething" starting even they'd still fire at the moment it's fine...yeah no there's no other solution as graphs goes. I must just do it even if it's tedious

#

At least from a single object starting point I can make a slower pseudo "for" like here to make sure not too many things runs at the same time

#

Actually, regardless of PixelCanvas I should add the NetworkSettled to the idle game now that I know it's a thing...Just to make it a bit healther at higher speeds

dense owl
#

finally, I think it worked...

#

well the rest is too much for my lack of sleep, I'll continue tomorrow

#

Thanks again for the help (like, really. being able to bulk drag&drop will be life changing in terms of saving time xD)

dense owl
# visual cargo ok so ideally you make a U# script that lierally all it does is `public GameObje...

Oh, I get what you ment by that now!
Once I copy the reference starting state, I don't need it or even to communicate with it since I already have valid arrays inside the manager Graph. That also means way less networking between different scripts. Took me long enough but I think I get it now.

Only issue I see is to define when it needs to be set and when it's already valid. (to not reset everytime the player rejoins)
Since a default empty array is of length 1 I guess I could check that before sending the initialize event (or just save a "Is_ArrayReady" bool)

ruby peak
#

hey guys, could i get help with understanding how the rate limiting works?
I've been getting reports from my players that they are losing their data outright or not saving the most final player data. I am guessing it is due to the player data being limited by the amounts of updates its sending but I am quite unclear when it comes to networking, the screenshot is a snippet from the debugger.
Is my assumption right or could there be something else at play?

wary summit
ruby peak
limber goblet
#

is it possible to suppress this message? vrcTupDead it comes up when you use FindComponentInPlayerObjects and I'll have like 40+ of them later on which will be very funnyyyy. If its editor only I don't mind

dense owl
#

isn't that the whole point to tell you it found something when you call FindComponentInPlayerObjects tho? xD

limber goblet
limber goblet
#

Waait can you send a network rpc like this, when you're not the owner of this player object? the rpc gets blocked for some reason, although I'm trying to tell the owner to handle incoming requests
Upon requesting, the master of a system will send a response back to the one that requested- similar to this:

otherPlayersPlayerObject.SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RegisterSuccess");

Like yeah, I know that I can't take ownership of it, but why is the rpc blocked as well? We can hide functions with the _ from network calls, so I thought that should be possible
(maybe my code is cooked one sec)
Update: Console says it's blocked but the rpc call is getting processed heckkkkk

wary summit
limber goblet
#

as of right now, I'm syncing playerIDs so I can access them via a list
I could still create a seperate list where I save the cached results but that's work xd

wary summit
#

it's an object reference, what do you mean you need to sync it?

#

yes, have a separate list or dictionary where the components are cached locally

limber goblet
wary summit
#

moderately, yeah. It's definitely doing some work

#

the exact cost doesn't matter, what matters is that caching it inside your script is a free performance boost

limber goblet
quick imp
#

Is there a way to directly refer to a persistence object when calling custom events for them? so far I only know of calling upon them as gameobjects so am currently using a "middleman" script to send data to them

#

Or rather can you have a gameobject save its parameters without making it into a playerobject?

dense owl
quick imp
#

hmm, lets see

#

So Im using an object to keep track of all the stats the player has

#

But it needs to be referenced for logic to activate things in the game

#

How do I ue this playerdata?

visual cargo
#

dios mio

#

well the big difference in PlayerData is that it doesn't have to exist on a GameObject or one specific script; it's data that's part of the player

quick imp
#

Oh ya? can I make veriables on a playerdata?

visual cargo
#

pretty much. but you probably only want to use PlayerData to save and load the data, but when you actually want to work it, you put it in a variable

#

you could adapt your current middleman to just save and load the data to PlayerData instead of relying on PlayerObjects saving it

quick imp
#

That sounds good, how can I set up a playerdata?

visual cargo
#

the link I posted is the doc page for it

quick imp
#

Oh yes

visual cargo
#

you essentially use the OnPlayerRestored event, which fires once all persistent data is loaded and ready, and use it to either store the data to variables to work later, or (if you detect the data is not there yet), create default values

#

then you use the functions for the various types, like SetInt, SetFloat, GetString, TryGetString, to save (set) and load (get) the data

quick imp
#

Oh I remember now I was told about this, Playerdata creates itself right, you dont manually set it up I was like "Saywhahhhhhhh"

visual cargo
#

well. yeah kinda I guess. you have to tell it to save and load the values and stuff

quick imp
#

Lets see... I dont think Ive tried it before

#

Well at least I can stop using the "persistence save" as a persistence object so i can target it with event custom without having to middleman wireless transfer that shuzz lol

dense owl
# quick imp Oh I remember now I was told about this, Playerdata creates itself right, you do...

PlayerData can be called by local or normal networked objects, they don't need to be PlayerObject.

For PlayerData I just make a dummy UdonBehavior to note down the key names.
All categories of the dummy are strings, the names reffer to which key types the names reffer to.
(So the "Key_Bool" are names that point to Get/Set Bools nodes specifically, etc)
But there's obviously better ways to keep track of that... ๐Ÿคฃ

You can either use the keys directly, or like suggested use variables like you'd normally do and just have:
For Loading
"OnPlayerRestored -> Set <variable> value to <key> value"
(initialize variable to match the key on rejoining the world)
For saving
"Custom event -> Set <key> value to <variable> value -> request serialisation"
(update the key to the variable's value, request to sync the data with server)

quick imp
#

Im reading up on the article, I have a pretty good idea on how to implement it

dense owl
#

PlayerData is pretty easy to use, and not having to constantly reference objects cause you can call the key from anywhere is suuuuuuuch good QoL it's fun to use

quick imp
#

In hindsight having my savedata not set up correctly has actually made it easier to quickly implement and debug a feature lol

quick imp
visual cargo
#

neat

fading totem
# quick imp

Please save your scene in a different folder than the VRCDefaultWorldScene.
Afaik the VCC still deletes and re-adds that every single time the sdk is updated.
If you're not using some sort of version control software, this can easily lead to lost work.

dense owl
fading totem
#

It's so cursed.

dense owl
#

It is...Especially for the most generic ones xD

quick imp
#

I tend to backup every time I do any sort of upgrade, so what happens? the scene just deletes randomly?

visual cargo
#

I just upgraded the SDK and it did not overwrite VRCDefaultWorldScene ๐Ÿ‘

sturdy veldt
#

It's taken ages of writing and rewriting code to figure it out but I've finally integrated saving with my procedural map generation system :D

dense owl
#

Cursed question:
Let say I have a "username check", then after it the object only interact with the user of corresponding name.
Would a single key work without conflict (since in theory only the whitelisted user can interact with their assigned object in the world) or do I need a custom key name per object?

If so, do all these keys count toward the total of data saved for everyone, or only the one the player is assigned a non null value? Since the object check for username before doing the persistant part, the key shouldn't ever be called on anyone but the intended player.

I'm a bit confused, since I guess they still all exist on world side, but wouldn't be used by everyone (for other checks I set a normal sync variable) I'm asking that because I was about to only use one key name (the object would only check its owner's key) and was aifraid it may conflict..

velvet barn
#

Why is persistence needed for this?

velvet barn
dense owl
#

It wouldn't need any save if it just redirected to "home" (or if the player tell me their target world beforehand, but it would be a pain for maintenance if I had to edit and reupload every time, so I just let players edit it themselves)

#

Basically:

  • Player get assigned an appartment they choose in the world (static value no saving needed)
  • Player can set a destination to leave when entering their fake appartment (edit at will, need saving the string)
  • Because it's assigned by username, only that one player can see their own door's menu (hide on start if check fail, no saving needed)
  • Player rejoins in front of their door (static value no saving needed)
#

Probably just a case of me overthinking, in practice everyone have their own value for "YourPortal", there's no reason for it to bleed on other doors unless I mess up OnPlayerRestored

lament mason
#

I hope it is fine to post here, I migrate the unity version it was 2022.3.6 and I just update to the newest version 2022.3.22 and is taking an eternity this loading window...even I closed the project and open but still show this...any way to make this window finish please?

dusk brook
#

Hello everyone, I have a question about saving a string with persistence. I tried saving a string of ~600 characters, it loads fine on PC, but not on Android. Are there any extra limitations on Android? (feel free to ping me to answer)

dense owl
#

that's...A LOT of characters...

dense owl
#

depending on if you can make parts smaller if they're about different game mechanics in the world

dusk brook
#

I'm using a weak android phone to test and maybe because it's slow, data from persistence take more time to load

dense owl
elfin wren
#

Unless they forget to check which player was restored..

restive vigil
#

Is there a way to make it so that if someone activates a trigger in one world, then something will change for them in a different world the next time they visit it, using persistence?

visual cargo
#

in a different instance yes, but not an entirely separate world

#

persistent data is only per-world

restive vigil
#

Thanks for the reply, that's a pity.

dense owl
#

I found another thing to fix in my "player registered to a fake appartment's door" system. Related to the question I had last time about "should I make a generic key (and the world will hopefully call the object's owner data) or unique keys per player".

For I reason I don't understand, the system DO recognize the players (as in their menu is accessible on their own door, the menu of other players is despawn for them. And same for each registered player, so far so good)
BUT as calling the saved data (shared generic key name) goes...It update all portals to be the same as the late joining player's locally (or straight up break sometimes) instead of checking each menu's owner for processing the data of the owner.

I didn't really get an answer last time so I'll try to confirm again:
If I make a composite key string (generic key name + username) it would prbably get rid of the overlap, well as long as the player don't change their name...But then what?

  1. Would that mean all these keys are on everyone's data or only the composite key on the related player's data?
  2. It would need a failsafe to not crash when the player is absent, wouldn't it?
  3. I'd need to make arbitrary callls instead of relying on "OnPlayerRestored"...I guess?
  4. Else I guess I could move to PlayerObject, and find a way to teleport them where the specific door would be located...Maybe that makes more sense for that one?
twilit meteor
#

When someone loads on via OnPlayerRestored
Are you checking if the player is local or not?

New players could be overwriting crap

#

also I wouldn't use their name as a key. What if they change it?

You can use Guid.NewGuid(); for your keys instead

dense owl
#

OnPlayerRestored is here to make sure the check on everyone's keys isn't done before it's ready

dense owl
visual cargo
#

hm odd. It seems RequestSerialization() doesn't work on a PlayerObject(), but only in ClientSim.
Behaviour is Manual, only 1 client so surely they're the owner, but it simply does nothing when called, like when a player isn't the owner. But I do an ownership check right before I call it so the client would never attempt requesting unless they were owner! lol
and it works perfectly as expected in-game so I'm not too worried abt it tho
just added #if UNITY_EDITOR to emulate as if it worked so I can still test in-editor, but if anyone is interested you can try replicating the issue to see if it's a just-me thing or something

viral linden
dense owl
#

or at least should

#

guess it would make more sense to just have a generic refresh then...

#

Actually yeah, no real need to do it via data, just refresh the portal that's already updated for everyone else, just like the unsaved one is when another player joins. Guess I just overengeenered that part

safe wagon
#

Ok I have a weird persistence bug.

I have a script on a PlayerObject with a ton of code, but the relevant code is simply this part:

[UdonSynced] public int AchievementCount = 0;

// this method is only called if PlayerDataReady event already fired...
public void _UnlockAchievement()
{
    // some other code related to unlocking an achievement

    AchievementCount++;
    RequestSerialization();
}

There is another script that simple reads from this value and displays it on a UI, but otherwise does nothing to the value.

The bug:
Sometimes when joining the world, AchievementCount will be equal to a very specific value: 1065353216 even though there is only a couple achievements unlocked (out of a max 300).

I noticed that this value 1065353216 just so happens to be the integer bitwise representation of the float value 1.0f. So I don't know what that's about, but the code is way too simple for this to be something wrong with our code. Has anyone ever encountered this or maybe have some input?

wispy latch
safe wagon
#

I'll double check that, I was just thinking about that.

wispy latch
# safe wagon I'll double check that, I was just thinking about that.

Yeah I'd be curious how you are getting the value and inputting into the text field(?)
Otherwise the only idea I have is to try this instead:
AchievementCount += 1;
But it's most likely on the receiving side if I had to guess.
(The other option is something weird on their servers going on)

wispy latch
safe wagon
#

The variable was always an int. Changing to += wouldn't hurt to try, but would indicate bigger problems with UdonSharp/Persitence in general if that fixed it. I don't have access to the UI code at the moment, waiting for someone else on the team to get back to me.

wispy latch
safe wagon
#

You ran into a problem using ++ that switching to += fixed?

wispy latch
quaint night
#

I've seen this before on regular non-persisted synced values and saw the same kind of thing where it looked like a float was being reinterpreted as an int. It was actually the float value for a neighboring field iirc. I'm not entirely sure what's wrong but I have a feeling there's some bug with the serialization or how it keeps fields lined up between versions of a world

safe wagon
#

Oof... Sounds like more reason to just ignore storing everything individually, and once again just save all your persisted variables in a single json string.

candid bough
wispy latch
#

I've been using a single string of json that's been serialized from a dictionary and then saved with PlayerData. It's been going okay, certainly no issues like the above at least.

#

Idk, but I felt like it made more sense to structure persistence like that to me. PlayerObjects for me are more for in world sharing of data as opposed to saving it imo.

light laurel
#

i agree. playerobjects donโ€™t seem like the kind of thing for saving data, playerdata does

#

although, for something like persistent currency per-player, playerobjects seem easier for that kind of thing

wispy latch
visual cargo
#

isn't it less steps to implement persistence on a PlayerObject? All it does is save the last networked state; so if you already have it working with UdonSynced variables, all it takes making it persistent is one component

wispy latch
sturdy veldt
#

I have yet to use player data because everything Iโ€™m saving works fine in player objects. Wonder when Iโ€™ll run into a situation where swapping is necessary ๐Ÿค”

visual cargo
#

I would even hedge to bet that you'd never need to switch, if PlayerObjects solve your implementation well enough
I've got objects that:

  1. I want everyone to have a copy of
  2. have changes on these objects synced for all players
  3. have this data save persistently
    PlayerObjects solves these objectives so easily that it would just make it harder if, for some reason, I would need to convert the saving to PlayerData.
    A save manager system makes just as much sense, if your objective is to have all of the data all in one place though. There's no one solution to everything
#

I've got some other numbers that I deliberately don't want to sync, so PlayerData will probably be easier to manage it with

wispy latch
wary summit
#

Playerdata is an extra convenience layer on top of playerobject, so you have the option to use whichever is more comfortable to you

sturdy veldt
#

Honestly just supporting instantiated synced objects is game changing so far ๐Ÿ’œ

#

Saving on top of that is just icing on the cake

wary summit
#

Between those two separate features, there was an initial assumption that they would exist independently, but a change happened when there was a realization that the two of those features actually go well together to solve a singular problem which is spread across a wider area

#

That's the brief, abridged history of persistence at VRC

elfin wren
amber pine
#

I think i missed something everything was pretty much fine now i have 128 errors something about unity 5 not supporting rigid bodies etc anyone know a quick fix for this . Please help ๐Ÿ™๐Ÿผ

wary summit
amber pine
#

Yes

#

On a side note @wary summit you've helped me so much that you're on the permanent guest list for any event that I throw irl or vr much appreciated

wary summit
#

you can't put non-convex mesh colliders on rigidbodies. Convex is a simpler version of the collider, it's a toggle on the mesh collider which wraps it so that it doesn't have holes.

If you don't need the extra precision of non-convex then just set them all to convex

If you do need the extra precision, then the best option is to recreate the shape out of primitive colliders like box, sphere, capsule

amber pine
#

Oh boy, gonna be a lot of work

#

@wary summit thank you and high 5

wary summit
humble olive
#

i couldn't find this in the doc, and im new to too syncing things in general, what setup do you need to sync sliders and toggles ? is there a source that explains it or a tutorial, i just wana have UI sliders Synced for player so they dont have to constantly change them when they join the world

#

im using Cyantriggers currently for the setup just as a headsup

twilit meteor
#

or do u mean saving?

wary summit
# humble olive i couldn't find this in the doc, and im new to too syncing things in general, wh...

I'm not personally too experienced with cyantriggers, but they should have access to PlayerData. That should be the easiest way to get started with simple persistent preferences. If this is supposed to be a local preference that other people don't need to see, then it's not too complex, would look something like this:

  • make an udon script that has a custom event
    • Make the UI element send that event to the script
    • Have that custom event read the value from the UI element
    • Plug that value into a PlayerData key
  • Add OnPlayerDataUpdated
    • set it so that if the player provided is not local, don't do anything
    • Inside of OnPlayerDataUpdated, get the value from PlayerData
    • Apply that value to the world or preference however you want it to behave
    • Also apply that value to the slider or toggle with SetValueWithoutNotify in order to show the accurate state when it loads from persistence and prevent infinite loops
terse juniper
#

quick question regarding persistent variables on playerobjects:
if a playerobject with persisted data was removed during an update to the world, will the data for that removed playerobject be cleared at some point, or will it take up space until the player chooses to clear their data for that world?
if in a later update a new playerobject with persistent variables is added, can it potentially pick up parts of the persisted data of the removed playerobject? (even if that requires the new playerobject to be very similar to the removed playerobject)

visual cargo
wary summit
#
  • if you previously had data saved on a player object, it is associated with the network ID of that player object
  • if you remove that object and publish a new version, it doesn't immediately delete all player's data of that network ID, but the next time someone enters the world and saves data, it will overwrite the old version with a new version, and that new version will not include the data from that object.
  • If you add a new object and you want it to be independent, then you don't need to do anything special because new objects will never be assigned an old network ID unless you clear network IDs. They always take a new, unused one.
  • if you did want to reconnect a new object with the old data, then you would need to manually edit the network IDs to assign the new object to the old number (if you know what that number was)
proven valve
#

Hi, I need your help with the TLP UdonVoiceUtils setup. Could you please respond to this post?

proven valve
leaden flax
#

just changed it

junior goblet
#

[02:47:39.672][ClientSimPlayer] Failed to locate player persistence view ID for PlayerButton/SpinCounts
Has anyone encountered this error before? Just added a very simple persistence player object and it is throwing this error

junior goblet
#

Fixed it, for anyone who finds this with the same error: Had to fix some network ID conflicts in the Network ID Utility.

light laurel
#

So, i'm trying to set a volume slider and audiosource volume to 0.5, and enable a bool called shuffle by default. both variables are persistent, as i save the data after changing it, and load the data in OnPlayerRestored. but, even though i set shuffle to true, and the slider's value to 0.5 on start, when i test in clientsim with no playerdata, the volume is zero and shuffle is false. this makes me think it's loading the empty data in OnPlaterRestored. why would it load the playerdata is there is none? is there a way to prevent this?

void Start() {
    shuffle = true;
    volumeSlider.value = volumeSlider.maxValue / 2;
    UpdateShuffleIcon();
    UpdateIndex();
    InitalizeSong();
}

public override void OnPlayerRestored(VRCPlayerApi player)
{
    if (!player.isLocal) return;
    shuffle = PlayerData.GetBool(Networking.LocalPlayer, ShuffleKey);
    UpdateShuffleIcon();

    paused = PlayerData.GetBool(Networking.LocalPlayer, PausedKey);
    if (paused) Pause();

    var savedVolume = PlayerData.GetFloat(Networking.LocalPlayer, VolumeKey);
    volumeSlider.SetValueWithoutNotify(savedVolume);
    source.volume = savedVolume;
    if (logs) Logger.Log(name, $"Saved bool \"shuffle\" = {shuffle} <b>|</b> Saved float \"musicVolume\" = {savedVolume}", LogColor.Aqua, true);
}
#

This is the volume slider.

public void UpdateVolume() {
    source.volume = volumeSlider.value / volumeSlider.maxValue;
    PlayerData.SetFloat(VolumeKey, volumeSlider.value);
}
raw sigil
#

may be slient sim, may be actual behaviour...
just store some extra bool gotSettings or smth and if false, do default values.

#

so if player never touched them bool is false

light laurel
#

my logs actually confirm that it loads the persistence data even though there is none, because entering clientsim with no playerdata still gives me the log about what the saved values were

light laurel
#

yep, it's the actual behaviour

#

it kinda seems like a bug that it runs OnPlayerRestored even if they have no playerdata in that world

visual cargo
#

OnPlayerRestored runs regardless if they have existing data or not

light laurel
#

yeah, i feel like it wither shouldn't, or there should be a way to check if they have data or not

#

could i check if the keys have a value yet or not?

visual cargo
#

precisely, that's why it runs regardless

#

if it didn't run, it would be difficult to initialize data for a first-joiner

light laurel
#

maybe TryGetBool or TryGetFloat is what i want

visual cargo
#

yep the success bool will tell you if it exists or not

#

if you don't use TryGet, and a key doesn't exist, then the function returns the default value for that type

light laurel
#

okay, so this seems to be what i'm looking for then

// This
shuffle = PlayerData.GetBool(Networking.LocalPlayer, ShuffleKey);
UpdateShuffleIcon();

// Into this
if (PlayerData.TryGetBool(Networking.LocalPlayer, ShuffleKey, out bool savedValue)) {
    shuffle = savedValue;
}
else shuffle = true;
UpdateShuffleIcon();
#

that makes it a lot easier to set default values

visual cargo
#

TryGet returns the value of that key, not if it was successful or not

#

the out bool is if it was successful or not

light laurel
#

oh, that's kinda weird

visual cargo
#

it is, a bit backwards from how some other functions do it

light laurel
#

yeah, exactly

unique rune
#

wow that's.... just why.

light laurel
#

yeah that's kinda annoying, makes it a little harder to use

unique rune
#

I was just looking at my own code, seems I did it with a HasKey() check then a GetBool().

light laurel
#

ooooh yeah, HasKey

#

i forgot about that

unique rune
#

yeah as it is, I don't even know how I'd use TryGet, it makes no sense for flow control at all

light laurel
#

yeah, if TryGet wasn't backwards then i would use that

unique rune
#

yeah

light laurel
#

so this, is what i want

if (PlayerData.HasKey(Networking.LocalPlayer, ShuffleKey)) {
    shuffle = PlayerData.GetBool(Networking.LocalPlayer, ShuffleKey);
}
else shuffle = true;
UpdateShuffleIcon();
unique rune
#

I actually have this, not sure if I actually need to check the data type, but I was being defensive:

    myLocalFunc(PlayerData.GetBool(player, KEY));
}```
light laurel
#

i don't think checking the type is necessary, for a music player anyway

#

which is what i'm making

unique rune
#

sure, you may not need it, and I probably don't actually here either.

#

maybe I should just write a not-stupid wrapper.

unique rune
#

huh. the documentation on what the Try* functions do is really ambiguous.

#

the docs say it outputs "string value, bool success" but not where those are. The intellisense tooltip suggests the out variable is indeed the value, not success

light laurel
#

yeah that's waht i was thinking

unique rune
#

yeah and TryGetString() returns a bool but the out parameter is a string

#

this is why clear and concise documentation is SO important

light laurel
#

huh

#

so then it isn't backwards?

unique rune
#

doesn't seem so

#

I do remember reading this page and going "wtf" and just ignoring it for the moment

visual cargo
#

so it's the documentation that's backwards. even better

unique rune
#

I don't think it's backwards, I think it's totally unclear, it doesn't actually describe the method signature at all.

#

which IMO is a bit bizarre for API documentation

visual cargo
#

it says the output is "bool success", which led me to believe thats the value of if it was successful or not

#

but its not success, it's the value

unique rune
#

no no, that's success

#

what it doesn't say is how it outputs this

#

it doesn't say which value is returned and which is an out var

#

which again, is bizarre

#

the Get* methods do return

light laurel
#

i feel like someone significant should know about this

unique rune
#

but the TryGet* methods return a bool for succes and out the actual value

unique rune
light laurel
unique rune
#

if you want to put up a canny I'll gladly +1 it though

light laurel
#

i haven't done that before but i think i have an account on there

unique rune
#

it can just use your vrchat account

light laurel
#

yeah that's probably what i did

light laurel
unique rune
#

excellent

flint hill
#

Got an issue of Persistence data starting to get lost between instances, is there some sort of loss of data that may occur with too much persistence data for a world as additional values are added onto it, or something that may cause it to get lost between updates? Values have not been renamed at all.

#

Is there also some way to determine the overall persistence data payload size?

visual cargo
#

the size will show up in the logs when its being loaded, and persistence can fail to save if its too large

#

I don't remember if it appears when saving data as well

flint hill
#

Ahh, cheers. I'll dig in and look. It's not entirely failing, but I've noted some missing variables so I was wondering if it could be cutting off part of the payload or something.

#

Just to confirm this is what should be the payload size, correct;

[Behaviour] Sending 176 bytes of instance metadata over 1 bunches.

visual cargo
#

I think that's right

#

it should be logging an error, if there was one

flint hill
#

I'm not seeing any errors, which is extra frustrating. It's just decided to eat a few variables. Like the personal credit balance for my partner's save.

#

Is there no way to dump the whole persistence payload out to debug?

flint hill
#

Thankfully, I have found and have fixed the bug causing a loss of player credits

flint hill
#

So the Terrariums are meant to add a passive income tick. For some reason I cannot discern, for anyone not the owner of the game's master controller script would see it pull 0 and write 0 to your Personal Credit balance on the first tick. So I've stopped that tick for now til I can rewrite it.

#

What's especially odd is the PC balance is entirely local, and it happens while staring at the loaded PC balance so it wasn't like it was getting ahead of Player Restored completing. I even tried putting in a check for that.

dense owl
#

Zero-grove is it?

#

Not sure if your bug is completely related to persistence, I noticied that sometimes when buying an upgrade, and someone joins before you save, it reverts it to locked BUT still ate the money you paid (lost so much credits having to rebuy terrariums...)

#

Maybe there's other problems like that resulting in "variables being eaten" because it happens even within an instence

flint hill
#

Yes!

flint hill
#

Just so I have the process straight; A purchase is made, but someone joining after that but before you can save reverts it?

#

That's probably technically a persistence bug, in that it sounds like the new player joining somehow forces a reload of progress on their end, but as they're not the instance owner it's supposed to only load their personal credit balance.

flint hill
#

Ah-HA caught and fixed, thank you @dense owl. Turns out I didn't have an explicit check for local player on player restored in the upgrade controller, so it'd flag the incoming player locally for yourself and fire loadgame off.

dense owl
#

But yeah, that's why I was thinking yours was the same bug, or at least the same kind of flaw

#

.

"pull 0 and write 0 to your Personal Credit balance on the first tick"

...Kinda sounds like it try to do "Credits current + Passive income" before PlayerRestored, resulting in "0 + Passive" at this point in time.

Maybe add a small delay after OnPlayerResored (or a flag that gets turned on) to make sure it never tick before or on same frame (VRc is weird when it comes to operations order, it may run just before it should sometimes, so...1 frame delay is always safer)

#

That or a check only being true for master, resulting in the "false" branch being called even if the upgrade is active?

flint hill
#

That's what I thought too, but it seemed to fail consistently. I rebuilt the passive tick from scratch within the main game controller, which optimized things a bit anyway, so now it's only ticking for the master and just tells all players to update their own credit balance after it's done the station account. It fires a little slower now (once every five minutes), but I upped the credit amount per-tick to balance it.

#

Needless to say, if anyone runs into any more bugs in The Zero-Grove, do please DM me so I can fix them!

scenic oyster
#

hiii- does anyone know how to add persistence to a toggle?

#

i added it to a cube that is a toggle and this happens

visual cargo
#

that component is only for PlayerObjects

#

you'll need to save something like that to PlayerData instead

scenic oyster
#

literally a cube

visual cargo
#

there are two kinds of ways you can save persistent data; PlayerObjects, and PlayerData

#

they both work a little differently

#

The component you're trying to use, VRC Enable Persistence, is for PlayerObjects, it won't do anything unless the object has the PlayerObject component on it as well

#

based on what you're doing, you probably don't want a PlayerObject anyway. You want to "save" the player's selection to PlayerData instead

scenic oyster
visual cargo
#

no..... that's the exact thing I'm explaining you probably don't want to do

#

a PlayerObject will create a copy of that object for every player that joins the instance. If this is a toggle button for a setting, every player doesn't need their own copy, do they?

scenic oyster
visual cargo
#

right, so if it's meant to be local, it should be saved to PlayerData instead

#

PlayerData is sort of just like variables, they're just a name and a value (referred to as a key-value database)

#

to save a value, you use one of the "Set" functions listed on this page. For example, you can use something like SetBool to save a bool that's true if it's daytime, and false for night

#

you probably already have an internal bool that tracks the object's toggle state

scenic oyster
visual cargo
#

Java....?

#

huh?

#

this is Udon and U#/C#

#

oooh you didn't write any of your scripts.

#

unfortunately you need to write some Udon in order to have persistence in the way you want it to

scenic oyster
visual cargo
#

you could code in the Udon Graph instead, if the written stuff confuses you

scenic oyster
visual cargo
#

you can open the tab by going to VRChat SDK > Udon Graph

#

I would pin this tab somewhere

#

then you can edit any graph script by selecting it and clicking "Open Udon Graph"

unique rune
#

Wherein I put my script dealing with PlayerData on a VRCPlayerObject...

quick imp
#

Are we not able to save playerdata in the form of a list []?

#

Might have to use a FOR to get it done if not :L

#

Such a pain ๐Ÿ˜ฆ

quick imp
#

I assume a setup like this will be adequate?

wary summit
quick imp
#

Oh, Looking through the playerdata section of the Udon it didnt have any nodes for arrays

quick imp
#

Having a real issue here, these send custom network events are refusing to send to the event custom, Ive debugged using audio ques to the point where I know for sure its these nodes that arnt working, I can even directly bridge the gap and then the logic works but I need it networked...

viral linden
#

can u post the whole thing

quick imp
#

Its quite expansive, lets see...

#

So fixed update, it passes through some checks before finally getting to the network event, Ive used sound ques to ensure that every step of the process works correctly which it does, when I switch out the send custom network event with just bridging it works, the only thing that isnt working is the network event

viral linden
#

network clogged?

quick imp
#

Hmm, well it doesnt even trigger once

#

Tried deleting the nodes, re adding them, restarting unity

#

I definitely know the nodes are to blame, Ive debugged it to pinpoint these as the root cause

viral linden
#

u sure? try debug message, and check in game?

#

put a debug after the send custom events

quick imp
#

Ive never used debug nodes, Ive always just had it play a test sound whenever it passes through, and thats working just fine on test

viral linden
#

use debug, and see how many times it runs

quick imp
#

Oh yeah I know it fires once per frame (Im gunna put in a gate to stop it doing that once I get it working) Whats important is that I know the prerequisite checks are correctly working for it to then go to the networked custom event

#

So I know its working as designed

#

I know its not optimal to fire off a networked event once a frame I will stop it doing that but Im just trying to get it to fire once

#

Its going against everything I learned doing this...

#

Ghost in the machine lol

viral linden
#

that is the problem, it can't send every frame, that is way too often

#

i bet the network is clogged

visual cargo
quick imp
quick imp
visual cargo
#

you.... can use the console in game

quick imp
#

NANI!

#

Oh yeah using that menu I totally fdorgot

visual cargo
#

and sound is an interesting choice, given that there are cases where they will not fire

quick imp
#

I still like using sound ques to check stuff is working

visual cargo
#

debug info that I need to see, I usually slap into the TextMeshPro on an Update loop so I can always see it

quick imp
#

Using sounds does bug out if its called once every fixed update but so long as you ear it for the first half second you know its working

#

Oh yes text mesh pros I use for debugging too

quick imp
#

Ok so got back to trying to make it work, used custom events instead of networked custom events, worked.... Perhaps Udon devs just made it so that network custom events wont work under a fixed update node?

#

If thats the case a simple message telling you this cant be done would have been handy :L

quick imp
mental torrent
#

I'm trying to cut down on the amount of updates I'm generating while tracking player location and saving the data. There are other systems that are watching and using the persistence info, and having them check their portion of the data and do a string comparison to see if it's changed, doesn't seem that efficient. Is there a good way of checking "has this chunk changed since it was last loaded"?

wary summit
mental torrent
#

If I tried to save data that matched the data already in the playerData, would the info reflect that it did change, or did not

quick imp
#

I was told in the past that VRCplayerdata can have arrays, but I cant seem to find any such node, can ayone advise on this?

#

Above is how I originally planned on saving loads of variables in an array :L

wary summit
visual cargo
#

PlayerData can only do byte arrays right

quick imp
#

No playerdata setBool[]?

#

I mean I was gunna do it this way but if people say theres a playerdata array then Il do that instead

visual cargo
#

it's SetBytes there, that's the only type that can be an array

#

although I did do it in a really jank way with ints.

quick imp
#

Ooooh? Bytes... thats new to me

wary summit
#

huh I feel like I'm having a mandela effect moment, that's wild that it doesn't have other arrays

#

you might be right

quick imp
#

Ooof, alright

visual cargo
#

if you got a bool array you might be able to get away with casting them to byte?

quick imp
#

Well in this case then moving forward with this logic, it threw an error "Index was outside the bounds of the array" I assume I have to addition+1 for it to work

wary summit
#

yeah, I'd pack 8 bools per byte, but you'd have to do some bit manipulation which is clunky in graph

quick imp
#

Im new to bytes, so would have no idea

visual cargo
#

well, you've technically been using bytes this entire time

#

lots of them