#archived-code-advanced
1 messages · Page 127 of 1
ah, I was going by the %
yeah
You should look at the time values mainly
fair
I probably also need to figure out why that time thing wasn't working then
it's supposed to be what lets the math happen over several frames instead of one
I'd suggest fixing the linq part first
Well, what is it supposed to do?
compare the xRange and yRange lists to see which ones have matching index property values
So, basically get all elements in xRange that have an element in yRange with the same index?
yeah
Well, the simplest way would be a nested loop
for(x in xRange)
{
for(y in yRange)
{
if(x.index == y.index)
{
resultList.Add(x);
break;
}
}
}
Something like this..? This is pseudocode obviously
I'll try that, though I feel like that also kind defeats the point of this whole algorithm
wdym?
to avoid having to iterate over the entire list
Well, your linq seems to do it anyway
ah
So there probably was not a point in it in the first place
damn ._.
You could make it work though.
Assuming I get what you're trying to do correctly:
for(int x = startIndex; x < endIndex; x++;)
{
var elementX = xRange[x];
//refactor this loop in the same fashion
//for(y in yRange)
//{
// if(x.index == y.index)
// {
// resultList.Add(x);
// break;
// }
//}
}
Something like this?
ah, I think I see the misunderstanding here maybe
public class Umap_x
{
public int index;
public float value;
public Umap_x(int index, float umap_x)
{
this.index = index;
this.value = umap_x;
}
}
public class Umap_y
{
public int index;
public float value;
public Umap_y(int index, float umap_y)
{
this.index = index;
this.value = umap_y;
}
}```
the "index" property of these refers to their index in the original full dataset
which is kept so that we can instead go through the list sorted by coordinate value
then just call the datapoints by index once found
perhaps it should be renamed to originalIndex or something
I don't see how that is relevant to my example. Or the conversation so far🤔
isn't this assuming that we're iterating over the coordinate points by index?
No. It was in reference to refactoring this piece of code:
xyRange = (from x in xRange
join y in yRange
on x.value equals y.value
into matches
where matches.Any()
select x).ToList();
Which is the main problem currently
right. Unless startIndex is 0 and endIndex is the last index in the list, I don't see the difference between using for(int x = startIndex; x < endIndex; x++;) and for(x in xRange)
the index property value != the element's index in the list we're going through
Right. Then just keep it as the first pseudocode that I shared.
Or I guess, it was supposed to be value, not index.
for(x in xRange)
{
for(y in yRange)
{
if(x.value == y.value)
{
resultList.Add(x);
break;
}
}
}
no index was right
Might want to do approximation equality to avoid floating point errors too
I don't see index being used in the linq snippet
..that's probably why the actual search wasn't working
good catch lol
...performance has dropped significantly
Share the updated code
Sort by time
no allocations at least
I'm gonna take a wild guess and say that it's the iterations causing the problem though
Yeah.
at least we know the other parts of the code are doing their job
if there isn't a way to do this without iterating over every point, I think we're back to needing to change the actual method of search
this has been my life the past month or two, it feels like
I think ideally you want the xRange and yRange being arrays with the index being an actual index into the array.
if the purpose is just to confirm indices, they can even just be bool arrays that you set to true if the element at that index exists.
Then the search would be as simple as if(xRange[index] && yRange[index])
true, but with index being in reference to the original 680k length dataset, there'd be gaps in both arrays
That's fine. The gaps can just be set to false.
that still means we'd be iterating 680k times
unless we knew the lowest and highest index value of either list, I suppose
but that could still be 680k worst case
Actually, I take it back. I was too focused on that linq(not nested loops part). But it's kinda meaningless to do it without looking at the whole picture
So basically, you want to get all the testimonies that have value in a range between min and max?
yeah
which is I think why I was being recommended to use a K-D Tree earlier
which I do already have an implementation of kinda, but I didn't write it, it only finds the single nearest point as far as I can tell, and it's not async
and the only ways to do that by searching for fixed size areas are by either assigning XY indices to each datapoint based on what fixed size area they lie in, or creating arrays for each fixed size area
which at that point defeats the point of doing literally any searching because the whole reason why this function exists is to figure out which datapoints lie on specific terrain chunks
so you'd be basically storing every single datapoint in memory anyways

I'm trying to work on not being a defeatist, but this sucks a lot
genuinely feels like the final boss of programming despite how easy it initially seems to anyone I go to this about
like for gods sake, my job here is to make a data science visualization tool that runs basically realtime in VR on phone hardware with unstylized realistic graphics

Storing 670k points in memory, assuming each point just needs 3 properties for range query, is not even 8 MB.
that makes me wonder why I was ever told to avoid having it all in memory, then
So, assuming we keep this solution, sorting the xRange and yRange by index should help a lot technically. Or maybe even just the yRange.
And then you can spread it over several frames
What was the context of when you were told that?
months ago in here, when I first started working on this
We'll need to see the context of that conversation. But perhaps there was just a misunderstanding. Did they not provide an explanation?
they did, but it's hard to recall at this point
Well, it's not like that's relevant ATM anyway.
Unless you can do it without this method at all
if it wouldn't be too computationally intense to have what I guess to be a 2D array of lists, then maybe
but then again, we go back to the issue of the data distribution being uneven
which means if you're allocating the same amount for every list, in order to get everything each list needs to fit like at least 200 points
and a third of those lists will probably end up being empty
That's basically a 3d array.
The data type itself is not "computationally intensive". It's what you do with it.
right
So basically the issue we have now with a refactored code is that you have these 2 range that are sorted in an arbitrary way. Which theoretically causes most of the elments to be looped.
Random access is about the most efficient thing you can do, and is the reason why grids are so fast (faster than KD tree)
We can make it better by sorting one of the lists(the internal one), so that breaks are hit more efficiently.
You can do some napkin math to see how much memory is needed, I doubt you would have issue fitting them all in memory.
But honestly yeah, I'd rewrite the whole thing.
It's just a matter of using an existing solution and optimizing it as much as possible or tearing it down entirely in favor of a more efficient solution.
If you have enough time, the latter is preferred.
and also having an understanding of what approaches are gonna eventually result in a dead end several weeks into trying to get it to work the way you want
random access should (theoretically) be easy to implement quickly
I mean, it's not like it's a dead end. It works. And there are ways to optimize it.
The understanding of what would be better for a given task comes with experience, but you can never be 100% sure.
yeah, I'm just referring to everything I've tried before
I have 5 days and about 25 hours of paid work left to pull this off though
well, 4
needs to be ready before the 24th, so done by 23rd
just hoping I can afford another total rewrite
if it's just 3D int array, 4 bytes * 200 per tile * 500^2 tiles
200MB
that still doable?
Sounds like a question for #💻┃code-beginner
If it's within your memory budget, sure.
quest 3 has 8GB total
So, as long as your whole program consumes less than 8 GB, it's fine.
Minus OS kinda stuff I assume
right
...I can't figure out how to prealloc a 2D array of lists ._.
which I'm trying to do because I need a way to know how many elements have already been added to a specific tile
loop the array elements and initialize a list for each. Though, perhaps there a better way than using lists.
If it's just to keep a track of some number, maybe use a struct with an extra variable instead.
I'm trying to do it as part of it's class declaration
would the struct just be the list itself?
I'm still not sure what you're trying to do. If you do need a list, just use a list. There's no point in putting it into a struct
I need a 2D array of lists that's 500x500, with each list allocating 200 elements
Why not use a 3d array instea of a 2d array of lists?
see here
Make a 3d array of structs that contain an extra variable with whatever data you need
I can't seem to do array[0,0,].length
the third dimension is all of the potential coordinates that lie within a specific tile
I have no way to know how many will be in each
so ideally, I would use list's .Add()
Then just make it 200. And fill only those that should contain valid data
that's what I'm trying to do
I'm saying I don't know the syntax to do that
struct TileStruct
{
int[] points;
int count;
public TileStruct(int[] initialData)
{
points = initialData;//or copy
count = initialData.Length;
}
}
TileStruct[,] tiles = new TileStruct[500,500];
If you want to go this path, then you can't initialize the lists. You'd need to do it later.
... = new List<int>[500,500];
wait so how do you set the length of the points array?
You don't set the length. The length is equal to whatever you initialized the array with.
You can init it in the constructor if your want.
public TileStruct(int num)
{
points = new int[num];
count = num;
}
that would have to happen after the 2D array has been initialized though, right?
is that not what we're trying to avoid?
Yes.
I don't have a way to know the length of the array before it's added
No. You need to initialize all the stuff at some point.
Then use the best estimated max length.
where do I specify that then?
if not when it's initialized?
you do specify it when you initialize the contents of the 2d array
Assuming we're talking about the struct path, you're allocating the array with structs in the field initializer. But the structs in the array are empty/ default initialized. So you need to initialize them with the data that you want them to have.
if I'm going through the entire dataset element by element, how do I get the entirity of the data that goes into a specific tile first?
and wouldn't that mean I'm still allocating after initialization?
I'm trying to avoid what was happening earlier with the xRange and yRange lists
the only way I see to do this logistically is to create an array of length 200, iterate over every datapoint to find which ones go into the array, then add the array to the tile
and repeat for every tile
that can't be the best way to do this
It depends on how the data is stored in whatever you have initially.
But yes, it's likely that you'll need to iterate all the tiles once.
right, I want to make sure I'm doing that only once
And that being said, it might be wiser to actually just copy the tile data into your 2d array directly. Because extra lists/arrays would cause allocations.
Again, I don't have the whole context so I can't say anything for sure.
that's what I'm trying to say
this is the context
here
this is what I want to do:
- preallocate the entirity of a 3D array, whose z lengths are unknown
- for every datapoint, check where it's coordinates are, and add that point's index to the z of the 3D array, with the tile it lies in being x and y
if I'm allocating as I'm going through the datapoints, that defeats the point of what we've been trying to solve all day
This is not the context.
I don't know what exactly your tiles represent and why do they contain points? You'd think that a tile is the smallest unit of data. But this doesn't seem to be the case here?
tiles represent terrain chunks
Well, you can't preallocate something you don't know how big it is.
each datapoint in the game I'm making is represented as an object on the terrain
thus the coordinates
we have said so many times at this point that we can set it to a max of 200
I'm sorry I'm just getting frustrated and exhausted
Then set it to max of 200.
alright. with a 3d array of ints, do I have a way to check how many values have already been added to the z array of a specific xy?
that's why I mentioned not being able to do array[0,0,].Length earlier
because if I'm adding datapoints element by element, I need a way to know where in that array to put the datapoint
so I'll need a 3D array of [500,500,200] and a 2D array of [500,500]?
Yep
okay, thank you
it took me an hour to figure out how to define a single variable
I feel fucked lmao
You could do it with a 2d array of structs, but you will need to initialize them manually which might be less efficient.
Well, it's not just that. This decision involves how you'd work with it down the line, so I wouldn't say it's just as simple as defining one variable.
I guess you have an issue of not filling up gaps in your knowledge.
For example this simple error and the one before it: #archived-code-advanced message
You should try to understand why it doesn't work.
If you just ignore the errors and things that don't work and switch to solutions that do work, you'll never know the correct way. It would just come back to bite at you later.
that's fair. I'm just trying to focus on getting it done because of how little time I have
..alright, new problem
apparently with the current sample size, some terrain tiles still have 300+ points
... 400+ points
Then just increase the size
If you can afford it, go for it. But it's really weird. What kind of tiles are these? How big are they? Why would there be 1000 objects on a tile?
"tiles" are just chunks of terrain, 32m^2 in size ingame
there'd be over 1k apparently because the dataset has clusters that tightly knit
so I'm likely gonna have to make overall grid larger
more tiles, that is
1000^2 with 500 per tile is 2GB
I'm at least smart enough to have made the terrain generation procedural
so world size isn't an issue
even with that, it's hitting max tile capacity only 60k points into the dataset
fuck
Might want to investigate what your dataset looks like
I know what it looks like, I mentioned this being a potential issue
uneven distributions
public int[,,] testimonyTileIndices = new int[2000, 2000, 500];
fuck
it just straight up won't let me make a variable big enough

if my python fuckery is correct, I might be able to get away with filtering the dataset before populating the tiles
I'll just have to figure out how to get the full dataset functioning another time
What's on that line?
Are you sure?
Maybe try a native array then
yes
can you do those 3D?
No, But you can flatten the your 3d array into a 1d one
how much of a difference would that make?
It would be slightly less convenient to work with. But in terms of performance it should be superior
how superior, though?
less overhead
Can't say anything specific though
At the very least it's not gonna be slower
so I should make a NativeArray of length 2000000000?
Yeah. See if it throws the out of memory error.
That being said, it's weird that that error appeared in the first place.
Are you sure you were only having one of these scripts in the scene?
From my understanding, an array needs a contiguous memory space
So if it can't find one, it'll throw an out of memory exception
would that be happening here?
Could be
I wonder if you're just running low on RAM when this happens
I suggest restarting and running your game and seeing if this error magically goes away, an easy test
can't seem to figure out how to prealloc a nativearray
The third variant is what you need probably.
I have 64GB and this needs to run on a device with 8, I would hope not
I can only guess that it's due to the nature of how managed memory allocated.
To be safe, I'd keep an eye on the memory profiler(or at least the memory module in the regular profiler).
Memory can be fragmented to where you can't get a contiguous segment. Just speculating
Yeah, but I wouldn't think that would happen with 64GB of ram. Assuming they're not using most of it.
Yeah it's unlikely
Could be the managed allocator limitation. Like maybe there's just some internal limit to how much it can allocated in one operation and they simply don't have a specific error message for that.
unity is using a lot, outside of runtime
30GB? Holy shit
I've never approached that even using GPU animations
I suggest profiling for memory leaks or something
surprising people with how fucked my unity project is seems to be a running theme
my head hurts, I need a break
This is not neccesserily a leak or an issue. As long as it doesn't increase over time, it's probably just how it reserves memory in you specific sceanrio.
So, it doesn't seem to be documented very well, but chat gpt gave some info on a max object size in .net by default. Seems to be 2GB, so it's quite possible that you're just over that limit.
https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element
native arrays should be free of this limitation
how should I be accessing the array once it's 1D?
I wanna say modular arithmetic
You're compressing a 3D space into 1D, so you need to devise a way to do that. You need to find a reasonable way to segment it to map it
right, that's what I'm asking about
What does your data here represent?
xy are indices of terrain tiles
z is a list of indices from a dataset
it's to be able to grab all of the datapoints that fall within a specific tile and just call them by index
full dataset is 680k datapoints and the spread is nonuniform
I don't have a ready made solution, but modular arithmetic is your answer here to flatten the 3D array into 1D
That should be your search string though, flattening a 3D array to 1D
well with 2d array it would be something like index = y * width + x.
Yes, according to this stack overflow: https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array
But the inverse is what he needs, I think? I might be misunderstanding; but that's why I say modular arithmetic
Like, he'll be WORKING with a flat native array and need 3D indices into his existing array right?
right but I only ever need to access it by index I think
so I can just math the index
testimonyTileIndices[xTileIndex + yTileIndex * 2000 + tileIndiceLengths[xTileIndex + yTileIndex * 2000] * 2000 * 2000] = (int)testimony.index;
I think that's what I need
idk
Probably. Might want to test a few examples on paper.
Then you can create a utility function to not write it out every time. I'd also avoid magic numbers and use the actual array lengths instead.
Yeah, at this point you might be doing something wrong
Maybe use the memory profiler
gotta install it
also probably gonna use it tomorrow
I can't think about this right now without popping more advils
gotta message my employer with the "hey so uh we might not meet the deadline" email
and then also skip on easter tomorrow
I'm in hell I think
You can use the memory module built in in the profiler for starters
Im trying to catch up with this and why do they need a 8GB array? (basing this on new int[2000, 2000, 500])
500 is the max amount of points a specific tile can have, at least with current settings
without filtering and without changing the amount of terrain tiles, that goes up to like 4k or 5k
that number is as high as it is because the data distribution is way uneven
Hmm then may be wise to do a hybrid system where you split the data only 1 or two times (kd tree) to minimise the wasted space and need to allocate such a large single array.
With this kind of distribution at this scale, having a 3d array is gonna be inefficient indeed. At this point it's gonna be an issue just to run the program on your target device.
You'd need some kind of data streaming implementation.
Though, given the time constraints, using a 2d array of lists might be enough for now. Just make sure you allocate and initialize it once.
that's what I was trying to do earlier, I thought you said you can't preallocate the lists of a 2D array
You mean like having a 2D array of KDTrees?
You can. You just can't do it in a field initializer.
You'll need to loop it and assign lists in start/awake.
Or maybe init it lazyliy when the tile list is first accessed
how would you do that without us going back to the problem of having 125m allocs in one frame?
The issue was not as much with the allocations, but that they were GCed immediately. If you allocate it once and reuse the same memory, it shouldn't be as much of an impact.
And then you can also think about doing your processing async properly.
I think this is the best course of action given all the info that you shared.
I'm having trouble understanding how this would be any different from doing the 3D array
or what that implementation would look like
It would be mostly the same. Except that you would preallocate a list with smaller capacity(maybe calculate the median amount of object in a tile). This way you would balance between allocating a lot of unused memory(and thus reducing the memory footprint) and allocating everything during your processing(reducing the processing time).
Kd trees are just a way of having some dimensional area with some amount of children that reduce in scale. I think this concept is similar to what others are saying.
My shit illustation. You would want many dimensions for the dense areas and the less dense ones can stop earlier, depending on the depth it will let you reduce the total size of the structure to hold the actual data (if using a 2d array)
I suggest this again because of the issues of trying to have a large collection to cover all of this range
This can be pre processed (if possible)
A kd inherently ends up more dense where there are many points
It also doesn’t need ‚buckets‘ and scales to many dimensions better than trees that split on all dimensions
I'm not sure they can implemented given the time constraints.
Maybe get the current implementation working to a degree and then try to implement the kd tree path in the remaining time.
What query size are they going for anyways?
Yeah there's no way they simultaneously need to query the entire map or a tiny tiny part of the map that is so small that it contains nothing.
I think the profiler data had 64 calls to the search method that they had, so perhaps 64 tiles at any given time
Giving that illustration the map size is about 50x50, if they need to query a 0.1x0.1 area, and use 0.1 as grid size, that's only 1 MB memory and skips all the complications of a KD tree.
It seems like they can adjust the tile size, but if they use 2000x2000 tiles, each might have 500 or so data points(positions). That's where the 8GB come from.
The memory required to store the points themselves should not enter the calculation, no matter what data structure you use they must be stored, the only comparison to be made is the data structure itself.
This was just to store indices apparently
To be honest, if just the indices take that much, it's just gonna be impossible without some kind of streaming system.
yeah, 4 bytes * 500 points * 2000^2 tiles
it needs to be smaller so you can cut out the empty space making this unusable
though ideally there would only be about 50-100 max per tile, just so the terrain isn't completely covered
That's not how the calculation works.
Well, assuming you are doing List<Point>[,], if you were thinking Point[,,] then sure.
It was assuming they preallocate lists of some capacity
I think you should try with a 2d array of lists preallocated with capacity set to 50. This should provide relative balance between memory and processing time. However I'm still not sure how you're gonna deal with the actual data.
I don't wanna disrupt the support here, mostly just lurking for my own curiosity/learning but just a little curious about mentions of a 8gb array. With the Quest's OS in mind and the entire rest of the game + it's realistic art-style won't anything like this have to at max use far, far less in terms of memory?
The issues are 3d float position to index look up time and memory usage of this mapping right?
2d float position, but yes
Yep. Maybe around 7ish in total. Though I'm not sure for the specific platform requirements.
I know consoles like PS5 and Xbox only reserve some 500-1000mb for the system and everything else can be used by the app.
z axis positions are calculated based on the terrain generation code
not super relevant here though
You definitely don't need 8 GB, looking at that graph only ~10% of the grids will have any point at all.
yeah 7gb then minus however much it's gonna take to do the rest of the game. Could be not as big of a deal in this project but I've seen a lot of complaints that a lot of games run into memory issues with that much still
List<Point>[,] and keep the empty grids null. I'd be surprised if the data structure even goes over 1 GB.
the problem then is the allocations done afterwards
In terms of memory that's gonna be optimal. But then we're back to several seconds of loading time
Which is why I suggest to preallocate the lists with a median length across the data set.
I can have the load time take a few moments, I just need that to not happen in a single frame
Does load time even matter, do players actual expect your game to load instantly with this big of a data set?
it's VR, so what's expected is solid framerate
ideally locked to 120
Just have a loading screen or something, people won't care if it takes a few seconds to load but smooth as butter afterwards.
realistically, 90
Half life alyx has loading between levels and its fine
that's what I'd like to have if possible, we couldn't figure out how to do that so far
Just do it all on another thread to keep your loading screen running well
that's what I've tried to do
My implementation was either incorrect or fundamentally flawed
I don't see how either grid or KD wouldn't work for that.
Ofc it it produces a lot of garbage during the load then gc spikes return
the only KDTree implementation I have was written by a colleague years ago without intent to be used in unity, so no async functionality
it doesnt need to be async and probably shouldn't if you just want to distrubute it over many main thread frames
I'm not suggesting KD tree to you, since you are having issues with the bare basics. A grid can be done in like 10 minutes.
Well,get it working with a 2d array of lists first and then implement the async functionality.
I did have a class specifically made for trying to get async functionality working with a frametime budget, but that apparently wasn't functioning as it should
I'll try to get the 2D array of lists working once I have unity open again tonight
I want to remind you get 0.011 ms per frame for 90 fps, so you will have very little time each frame to split this work over that I'd advise against this. You should run it on a thread pool thread or unity job when doing the look ups/initial creation of this data.
Anyone good with A Star path finding Algorithms?
i've worked with it quite recently
Well, I'm in the middle of implementing mine, I have quite the specific issue with it
I've drawing the grid over my current tilemap, but it's showing random connected nodes which are outside the map but it's only a few, I've added a mask - lets call it avoidance layer which includes my water/obstacle/default layer. But they're still showing outside the designated area. I'm not sure if I'm allowed to send pictures but it would help you get a better visual picture
You probably need to share some code but I can only presume your "mask" is covering the area you think it is
Yeah, I just debugged it, the mask isn't covering those specific areas where strays are popping up
tyvm though big appreciate
🦆 np
Ok this has been driving me crazy for the last hour...
I have a function that takes input Vector3 and returns one of its values as an int
{
int dirX = (int)Mathf.Sign(inputVector.x);
Debug.Log(dirX);
}```
my input vectors go -1, 0 or 1
you would think that (int)Mathf.Sign(inputVector.x) is exactly the same as (int)inputVector.x
but apperantley its not??
if I enter a value that doesnt affect x, so x should be 0:
(int)Mathf.Sign(inputVector.x) returns 1 while (int)inputVector.x retunrs 0
```csharp
Debug.Log("input vector3 is: " + inputVector +
", Mathf.Sign(inputVector.x) is: " + Mathf.Sign(inputVector.x) +
", (int)inputVector.x is: " + (int)inputVector.x);
Debug Log: input vector3 is: (0.00, -1.00, 0.00), Mathf.Sign(inputVector.x) is: 1, (int)inputVector.x is: 0
Full Vector3 value: (0,0000000000, -1,0000000000, 0,0000000000)
TLDR for Vector3 (0.00, -1.00, 0.00) Mathf.Sign(inputVector.x) 1
why😭 ???
should use Mathf.RoundToInt() instead
oh..
damn, i really should have looked at the Sign function, but copilot wasn't wrong about these things before 😱
you are so right, it says return (f >= 0f) ? 1f : (-1f); one click away
thanks!
ai makes shit up
ye but usually about obscure functions or if you give it something big
i just started a new dialog and its still super convinced that Mathf.Sign is capable of returning a 0
guess they dont have it much in training data
actually i take my words back, ai gaslighting me is pretty funny
And non-conceptually for the rest of us real people
https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime%2FExport%2FMath%2FMathf.cs#L162
It seems to only consume 16gb at the moment. But you can inspector it further there's the inspect button next to the allocated memory distribution
that's idle, when first opening the project
not sure how to derive meaning from this ngl
the meaning seems pretty clear to me. You have two ultra-massive allocations. Are you loading something into NativeArrays? Is there a package loading data? It must be huge, or incredibly wasteful
the context is in the convo I mentioned
tldr, 670k datapoints of XY float coordinates, massively uneven distribution
the idea is to have the space for all of those datapoints preallocated so that we don't have an issue we ran into before, where 125 million allocs were happening in a single frame when loading in the dataset initially
to clarify, these datapoints are gonna be visualized as objects on procedurally generated terrain, and the datapoints to render are gonna be loaded in by calling the indices of the currently loaded terrain tiles
but random access is very much not gonna work here, at least with a 3D array
so we're about to try a 2D array of lists with only about 50 points preallocated per tile
670,000 * 8 bytes = 5.36 megabytes. This should fit into a few tens of megabytes in the worst case scenario with some overhead. 14.9GB is enough to store billions of float pairs. You must have a ton more info for each data point? Just with some rough math, you must be storing nearly 3k floats per data point?
the problem is the uneven distribution
some tiles (a lot actually) have zero points
some have over 4000
and that's with the total dataset distributed over a grid of 2000x2000
so, to alloc the max amount for every tile
2000^2 tiles * lets say 500 points per tile * 4 bytes for each datapoint's index in the original dataset
you can start to see the issue probably
and that's just with the 3D array
once that's alloc'd, you have no way to know how many points are already stored in each tile
so you then also need another 2D int array of 2000^2 tiles to keep track of each tile's array length
thus part of why we're swapping to lists
this is what you meant, right?
List<int> alloc = new List<int>(50);
for (int y = 0; y < worldTileLength; y++)
{
for (int x = 0; x < worldTileLength; x++)
{
tileIndices[x, y] = alloc;
}
}```
(in the start function)
I glanced over the context and it looks like this is a multi-day effort and probably only you really understands what needs to happen. Why does this all need to be in memory and accessible as fast as possible? It only takes a minute to look at your numbers here and know preloading all data is an instant fail if your memory target is 8GB
Indeed. That's the thing, it kinda doesn't. I have plenty of room for things to load in slowly, but the biggest thing I've been trying to focus on (when not being told to try something else) is just getting everything to not load in simultaneously
cuz I apparently don't know proper async/await or UniTask useage
and every attempt I've done at trying to make that work has made things worse lol
What are you doing with this data in memory exactly? Your assumption that every grid tile requires maximum allocated memory is fishy to me and blows up your memory space budget. You used conservative lists and there was some performance problem you're trying to solve?
Originally the way I was doing it was by just searching the original dataset for all of the points that lie within a terrain tile whenever said tile is active, and then storing that list with said tile in the scene. Issue there is that when you have 49 terrain tiles loaded in, that means 49 queries
and because the actual file I'm working with is a .parquet, the only variable type I can convert it into initially is a DataFrame, which really doesn't seem to like anything asynchronous
so now it's set up to convert that dataframe to a custom datatype as soon as it's made
which has several arrays of the dataset's indices ordered by property for optimized searching
does the actual file need to be loaded at runtime, or can it be pre-processed? and why not use spatial hashing? create a set of buckets for each tile, add all points from your dataset to a list for that bucket, do your queries in a target bucket (or set of buckets if you're searching by radius)
preprocessing is technically feasible, but since this app eventually needs to be easily modifiable to work with other similar datasets, said preprocessing should be easy to do from a dev point of view
not that I should worry about that right now, honestly
I just need a POC that can be demo'd before the 24th
I don't think we've looked into spatial hashing yet though
(I also need to figure out what that is lol)
seems like that's for 3D, no?
No, technically it works for any number of dimensions. Are each of these points associated with a tile, within that tile?
by default they're just arbitrary XY floats, so nah
part of my custom datatype's processing is assigning tile indices to each point, though
or well, it was
eventually swapped from that to vice versa, having the 2D array of tiles where the datapoint indices were assigned to whatever tiles they would be positioned on
I assume you mean your 2d array of tiles have a list of data point indices associated with each tile, and you would use the index to find the right data point in a 670k-length list of them
yeh
and why are you pre-allocating, assuming the worst case scenario?
well, for 3D arrays, because there wasn't another option other than having missing datapoints
no, the 4k points per tile
that's what I mean, the tiles which would have 4k datapoints wouldn't be able to story every datapoint associated with it
why not? resizable list for each
we're back to what are you doing with this data? there is a case to be made for performance if you know the lengths are fixed but it'll force you to stream data in from disk, and I'm confused about why you aren't taking the simple solution first
in short, this is an app where you can walk around in a giant desert with a bunch of a specific plant scattered across the terrain. Each of those plants is a datapoint, which you can go up to and select to view the information associated with it
what is the relation of points associated with a tile, then? apparently they're not related spatially
the only thing that associates it with the tile is the fact that the tile is in the same position as the datapoint
or well, that the datapoint lies within the bounds of the terrain tile
you said those points didn't necessarily lie within the bounds of their associated tile earlier
I just said they aren't assigned to specific tiles by default
they just get assigned to tiles after scaling
your architecture is now incredibly weird to me. It sounds like you have 670k plant locations and the tiles don't really matter
another part of the reason why I have those positions associated with specific tiles is because all of the plants are being rendered with GPUI, so none of them are actual ingame objects. What that means for selecting a specific plant ingame is that you instead have to just search for whichever datapoint is closest to whatever point your selection raycast hits
I currently do that search by having each tile with it's own KDTree
so you have 2k * 2k kdtrees? why not one? I assume it's not being rebuilt often, if at all
no, the KDTree search system was implemented before we started trying to store every single tile in memory all at once
the KDTrees are generated as the tile is loaded in
And around we go. The tiles are loaded in one at a time now? If you already have that working, just don't load all the tiles all at once like it seems like you're doing
if it's not performance costly to query, a single kdtree could work
the tile gameobjects are loaded in one at a time, yes
not loading them in all at once has been what I've been trying to do the whole time lol
Time to pre process the data into a file per tile and load them as needed
Automate it in the editor so it's easy to do on other data in future.
How do we go about doing that?
easy, write some code for use in editor (via menu option or scriptable object) to read the data and output it in a better format for use at runtime, such as being pre sorted per tile.
well, yeah, I figured that much
you know your data base right now so you know what needs to be done to make it usable at runtime
Right. I'm moreso asking about what the process of doing that actual preprocessing looks like
No. You'd need a new list for every tile😬
like this, then?
for (int y = 0; y < worldTileLength; y++)
{
for (int x = 0; x < worldTileLength; x++)
{
tileIndices[x, y] = new List<int>(50);
}
}```
But we know it uses too much memory to pre allocate all the lists as many are empty 🤔
for arrays, yes. The idea was to use Lists as a middle ground and only allocate a small amount for each tile initially
Just keep the tile empty until you need to put a point into it.
new List<int>(50) still allocates an array of length 50
then nothing is allocated and we're back to 125m allocs in a single frame lol
the point of this is to avoid a few resizes + re allocations as the list grows
No? You allocate as you go through the points and put it in the grid.
You load the whole data set, get params for your tile sizes and positions, make new scriptable object/file for each tile, find all data that exists in this tile, add to asset (and maybe also build a KD tree for this tile to speed up finding the points even more later), save asset, repeat!
Then they get lots of issues with GC which we went over days ago...
I understand that, I'm asking about what literally should be written to do this lmao
I don't have any experience with making files like that
GC doesn't matter if it's something you allocate and holding onto.
the list resizes will have some but i dont know enough to know
wh-
Set the point count to 1000000, map size to 2000, and building the grid takes less than a second on my computer, while querying the grid for nearby points takes less than 0.1 ms that the browser cannot even accurately measure it. And this is all in JS running in your browser, so C# should be magnitude faster.
this is also a fairly even distribution of datapoints
It's not even, I have the randomizing biased towards 0,0
But the more uneven it is, the less memory it takes up.
The memory usage is only ~45 MB without accounting for the points themselves, if you count 24 bytes per point that's still well within 100 MB.
do each of these points have indices associated with them?
The grid just stores pointers to the points, it would take even less memory if you store points via their indexes instead.
wait so how does this work? I'm kinda having trouble parsing it
It's just a 2D array of lists, exactly what you are doing.
I was just curious and wondering what the memory and performance characteristics look like so I wrote a small demo with configurable point count and map size to play around.
I mean, definitely not, if it's fast enough to be running in my browser lmao
(Well and also making sure I'm not giving out wrong advice to people)
it's almost demoralizing how well this does what I'm trying to do lmao
Well, once you're loaded, it is fast in your scenario too.
right but even the loading takes less than a second
The code is not exactly written in high standard it's just a quick demo I whipped up, but L28 is the code of building the grid, L58 is the code of querying nearby points.
wait so where are the lists? all I see is Array and Set, the latter I haven't seen before
Js arrays work the same as a c# list, expand as needed
ah
A C# list wraps an array and handles reallocation of the array when it needs to get larger or smaller for you.
This is important to know, pre allocating a list with 50 as it's capacity means it already made an array of size 50
This is good if you know you have 50 things to add as we avoid a few resizes to get to 50 at the end
If you have 2 things to add... Bad
it seems like they're just using a 1D array for the grid though
A 2d array in c# using [,] is actually 1 array with maths to calculate the index, usually x + y * width
[][] is different, that is an array of arrays.
right, but isn't this supposed to be a 3D array?
or well, equivalent to a 2D array of lists?
I'm still kinda flabbergasted by this, like I've spent literal months trying to figure this out
this has been the #1 obstacle for this entire project, we'd be out of business in like 4 days from now if we didn't get something even a 10th as effective as this
I just feel incompetent now
Well the intention of the demo is certainly not to demoralize, but feel free to play around with it and use its code as reference. The relevant meat of the code is just these two parts, you can ignore all the other code for stuffs like update loop and input handling.
I don't know JS so I might need some help figuring out what all's happening still
what's going on with the ??= [] on L32?
JS ??= is the same thing as C# ??=, [] just creates a new empty array.
Hey guys, How do I capture collision and trigger data of child game objects on a script attached to the parent?
2D physics
I'm just still totally confused by how this is running as fast as it is
there's not even anything async or multithreaded from what I can tell
I'm just trying to figure out what's making that much of a difference
Would this be equivalent then?
List<int> tile = tileIndices[xTileIndex, yTileIndex] ??= new List<int>();
tile.Add((int)testimony.index);```
Yeah, it's a fancier way to get or initialize, then add into it.
I think the demo code can pretty much be translated line by line to C#.
this doesn't seem to write anything to the tile in the 2D array
List is a reference type, the tile at that index in the array points to the same one as the variable.
Ah. For some reason, this line is giving me Object reference not set to an instance of an object
for (int i = 0; i < tileIndices[(int)tileIndex.x, (int)tileIndex.y].Count; i++)```
The idea is that only the tiles that have any point at all will be initialized, and the empty tiles are just null to save memory. You need to null check the tile before using it.
It did for you as well at some point. I remember when you still had linq it was around 500 ms or something
Here
if something often expanding/decreasing alot and you want to have 0 allocation you can just use ArrayPool<T> . The key here you'd need to either use Array.Copy OR Buffer.BlockCopy to transfer them over
OR
Custom List<T> with ArrayPool<T> as the backing array
Array.Copy is the general-purpose version of Buffer.BlockCopy, so the perf should be almost the same for most use cases AND much safer
inb4 some folks doubting the perf, Array.Copy/Buffer.BlockCopy is hella fast and it's what being used in the backing array of your beloved List<T>
What I said was in context of their issue
The problem originally was lots of garbage during creation and now it's too much memory usage.
Hi, is there any way I can specify multiple types here. For example, I have MonoBehaviour. I would like to add NetworkBehaviour as another option
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
no, that "specifying" a type here is inheriting from MonoBehaviour and C# does not support multiple inheritance. just create another singleton class that inherits from NetworkBehaviour if you need that
You probably wouldn't want to because the logic you would use for destroying a duplicate network singleton would not be the same.
You would want to declare a new NetworkSingleton class probably with network aware instance management
how do I do this webRTC stuff?
The 2D array of lists is kinda implemented now, but for some reason either none of the data is actually saving or none of it is being read
either way, trying to access any of the lists results in a zero length list
private async UniTask PopulateTilesWithTestimonies(List<Testimony> testimonies)
{
foreach (Testimony testimony in testimonies)
{
// + 18 to make every value positive (lowest value is -17.75)
int xTileIndex = (int)Math.Round(((float)testimony.umap_x + 18) / plantMapSampleScale, MidpointRounding.AwayFromZero);
// + 17 to make every value positive (lowest value is -16.61)
int yTileIndex = (int)Math.Round(((float)testimony.umap_y + 17) / plantMapSampleScale, MidpointRounding.AwayFromZero);
List<int> tile = tileIndices[xTileIndex, yTileIndex] ??= new List<int>();
tile.Add((int)testimony.index);
//Debug.Log($"x = {xTileIndex}, y = {yTileIndex}, length = {tile.Count}");
}
}```
this is what I'm using to populate the lists
public List<Testimony> GetTestimoniesInTile(Vector2 tileIndex)
{
//Debug.Log($"x = {tileIndex.x + testimonyTileCenterOffset.x}, y = {tileIndex.y + testimonyTileCenterOffset.y}");
List<int> tile = tileIndices[(int)(tileIndex.x + testimonyTileCenterOffset.x), (int)(tileIndex.y + testimonyTileCenterOffset.y)];
List<Testimony> testimonies = new List<Testimony>();
if (tile != null)
{
for (int i = 0; i < tile.Count; i++)
{
testimonies.Add(this.testimonies.testimonyArray[tile[i]]);
}
}
//Debug.Log($"testimony length: {testimonies.Count}");
return testimonies;
}```
and this is what I'm using to access those lists
How do I actually use BFS algorythm, Ive looked it up an dI now know how do the algorythm and get an ordered list of all the connected noeds but how do I actually get the shortest path from a to b now ?
op wait, it's def being stored. I'm just either sampling from a bad point in the dataset, filtering too much, or setting the data rescale too high
yeah that's fixed. Next is just figuring out why I'm still getting a big frametime spike
Glad that's resolved. Do consider pre allocating the testimonies list to tile.Count
Btw the tile list could be Testinomy as its a reference and will mean you dont need to build a new list each and retrieve them.
(Think of it as a std::vector<Testimony*> if you know cpp)
I can't if it's null lol
not sure what you mean here
you could allocate a reasonably sized pool of lists ahead of time and use those rather than allocating new ones in the loop
the length of those lists varies way too much for that
like a third of them don't even get populated
i think rob also means passing an initial capacity into those lists so they don't need to allocate new memory when you call Add? if you have some idea of how many individual entries will be in most tiles, setting the initial capacity might help a little
so make your pool 2/3 the size of the total? 😛
for context, this is for a dataset of coordinates that are gonna be represented as objects on a procedurally generated terrain
the spread is extremely uneven
and there's 670k of them
that's why you want a separate pool, i'm not saying preallocate one for every single location
I'm not sure wym
the amount in any given tile can also range anywhere from 0 to like 4000
is this a one time thing?
tile data is read from every time a terrain tile gameobject is loaded in
if (tile != null)
{
List<Testimony> testimonies = new List<Testimony>(tile.Count);
for (int i = 0; i < tile.Count; i++)
{
testimonies.Add(this.testimonies.testimonyArray[tile[i]]);
}
return testimonies;
}
else return null;
an example of what i mean
We know already the amount we will add to the list so its best to set the start capcity of the list.
in PopulateTilesWithTestimonies you don't know the size of each tile list ahead of time, but you could maybe try doing a separate pass to count the items at each location first without adding them to the list! if the amount of memory allocations is your main problem that would let you pass in the capacity there too
This optimization highly depends on the distribution of data. List resizing generates garbage which this optimization aims to remove, but keep in mind that doing a first pass of the data to calculate the counts of all tiles also requires you to temporarily store the counts somewhere, which afterwards also needs to be garbage collected.
yeah, but a single array of counts should be less allocations overall than potentially hundreds of list reallocations (i'm responding to the previous discussion about memory allocations being the problem with this code here, i don't know if it's actually any faster to do this overall)
They have a dataset of 670k points in a tile map of 2000x2000, if you store the counts in first pass in an int[,], that's already ~15 MB of garbage.
Without knowing the distribution of the data we cannot really calculate how much resizing will occur, but if we assume uniform distribution, 670k points across 2000x2000 tiles means each tile only has 0.16 points, no resizing at all.
this is why I still think this data should be pre sorted and stored for each tile but hey ho 🙏
they said the spread is very non-uniform and some tiles have 4000+ items so i'm guessing those are where the problematic allocations are happening
I don't think the math of this optimization still checks out.
I could be remembering wrong, but list starts off with a capacity of 4, and doubles every time it runs out (8, 16, 32, etc).
For a tile that contains exactly 4097 points (worst case scenario), it would have to resize and cause 4 + 8 + 16 + ... + 4096 = 8188 x bytes taken for each item amount of garbage. Assuming 8 bytes per pointer, that would be ~64 KB of garbage, and you would need 240 of these tiles to generate 15 MB of garbage, for the optimization to make sense. However 240 of these tiles already contain 983k points.
the counts could be in a dictionary or something if it's mostly empty squares, but i guess the point is that whatever it is you could reuse that between calls so it's not being allocated every time like the individual lists
I doubt that even with a dictionary the optimization would still check out. But either way, this is during the loading screen, as long as the amount of garbage allocated is within constraint then it doesn't really matter, and 15 MB of garbage is hardly something the target device cannot handle.
Entities people! does hybrid rendering handle view frustrum and umbra occlusion culling?
also how do you send an instance material property block?
in doing everything with jobs and at this point i might as well switch to URP and use ECS
right, here's the rub; i have a website, or at least a URL created by the UE5 Remote Control API, and I want to get a unity script to manipulate the events through the URL
did anyone try this thing out before?
danke
Yep I tried it once but give me headache but I try and contact the live support desk team
htf does any of this make sense
guys is it possible to do something like this in unity? so basically that a circle has a radius of a certain color, and when that radius comes into contact with another radius of a different color they form a border between eachother, like how it is in the image
Not out of the box. Depending on your needs you can most likely gets there with shader with multi pass/stencil buffer.
Stencils sounds like the idea but if you want the edge outline you'd look into intersection shaders
i assume ill have to use both right?
You can do both in the same shader yeah
If you want to use shader graph though you'll do the intersection in the graph and probably use pipeline render objects
hey guys! i wonder is it possible with the water surface to displace the water by a ship? i know there are decals and such but I wonder is it possible to actually change the geometry?
I seem to not be able to make physics that feel good without this because the ship does not influence the water around it
btw where do i write the code for the stencil buffers?
Shaders can write and test the stencil buffer. This can be used to control when a shader draws:
https://docs.unity3d.com/Manual/SL-Stencil.html
Depends on how much control you want. You can use Renderfeature, but you can also use directly shader. That being said, it will most likely be terrible in performance. Not sure you can make something that runs well given the nature of dependence between each render.
Having some issues w raycast commands, its absolutely insistent that my results buffer is too small when using 2 jobs in the same fixed update
boundsCheckHits = new(boundsCheckCommands.Length + 1, Allocator.TempJob);
JobHandle jh2 = RaycastCommand.ScheduleBatch(boundsCheckCommands, boundsCheckHits, 1, boundsCheckCommands.Length + 1);
jh2.Complete();
every time I run this code, it says
The supplied results buffer is too small, there should be at least maxHits space per each command in the batch.
OH wait hold on i've just realised, its maxHits PER command
okay, fixed that issue
only problem now is that it just won't hit anything
all of the results come back null
Because SerializedObjectView is a view on top of PackedBinaryStream this means I can't just store views for later deserialization?
You'd need to show the rest of the code if you need help with that
i figured it all out, turns out I was being dim and I was just plain missing the raycasts. I've amended the casts themselves and everything works as expected :)
"name": "Game.Server",
"references": [
"Game.Shared"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true
}
Ive got an asmdef for my server build but all my packages arent being automatically referenced? how would i fix this
What do you mean by this exactly? What issue or error are you running into?
errors like these but its because i havnt referenced the pacakges in the references section
im just wondering how id automatically reference all packages im using
Does this code live in an assembly definition as well>
Autoreferencing only works for code that isn't itself in a specific assembly definition.
i have 3 folders inside my script folder client shared and server which contain all the scripts for each build so server folder contains server asmdef
for code that's in another assembly, you need to add your assembly as a dependency to that assembly
then yeah you need to add any other assemblies you need references to as dependencies
oh alr 😅 no way to automate it ig?
Not that I know of. I can't imagine automating it would ever lead to anything good TBH
you don't want all your assemblies to reference all your other assemblies
for one - you'd have circular dependencies that way
👍 alright thanks for the help 😄
yea i see what you mean
Code design question.
I have a player with inventory in my game. Different items can have different associated actions and info specific to them.
For this example:
I want to be able to place selected item only if it supports it.
How do i keep my code structure CLEAN?
I have this:
class Inventory{
UsableItemSO[] items
}
abstract class UsableItemSO : ScriptableObject{
List<ItemActionSO> itemActions
PerformAction(owner, actionIndex){
itemActions[actionIndex].Perform(owner)
}
}
class PlaceableItem : UsableItemSO{
size
sceneObject
}
abstract class ItemActionSO : ScriptableObject{
actionInputKey
actionName
Perform(owner)
}
class PlaceAction : ItemActionSO {
Perform(owner){
//needs some specific values from PlaceableItem
}
}
When a player provides corresponding input I call currentItem.Perform(gameobject, actionIndex).
Question is: how do i get the info needed for PlacePreviewAction from PlaceableItem that it was called from?
unwanted solutions:
I can't just find player gameobject and get it's currentItem: it hold a reference to a UsableItemSO. I don't want to downcast.
I can't add UsableItemSO to Perform() arguments: same reason.
I can't have PlaceableItem as UsableItem field: some items are not placeable and i don't want to have unrelated fields.
I can't have needed fields defined in concrete itemAction class (for example i can't have size defined in PlaceAction): it is wrong due to SRP.
why not have ItemActionSO be generic so you can have PlaceAction correctly get PlaceableItem without casts?
e.g. ItemActionSO<T> where T : UsableItemSO
otherwise perhaps an interface for actions is better so place action can be made with ItemActionSO in mind
With how you've set this up, I dont really see what alternatives you think are possible other than PlaceableItem trying to cast ItemAction to PlaceAction
Even if its generic, you eventually come down to the exact same thing: placeable item and place action rely on each other.
The only way I'd see here to not rely on each other would be some god class containing every variable, which you can pass to any ItemAction. The derived classes would read the values it wants (and still relies on the item setting values properly!). This would be bad for obvious reasons
List<ItemActionSO> itemActions is the problem because if you want all actions in 1 list that is inherited then you cant really get around needing to cast later
I don't see alternatives too that's why I'm asking. Downcasting must be avoided as a bad practice
its an up cast from ItemActionSO -> PlaceAction
your design has forced this requirement
bleh i mean to UsableItemSO
abstract class UsableItemSO : ScriptableObject{
List<ItemActionSO<UsableItemSO>> itemActions
This may work if we then have class PlaceAction : ItemActionSO<UsableItemSO> { right?
im not really sure if this would be feasible either given the current classes. Youd have PlaceAction : ItemActionSO <PlaceableItem> meaning the SO has to also store the specific UsableItemSO, so you cant really reuse them.
Ah, is the issue with trying to create functionality with serialized SOs...
having everything as SO here doesnt seem like good practice either
id just downcast here unless you really want to redesign this. you can spend days trying to go into best practices to convince yourself your code is decoupled. At the end of the day, it really wont be
These are the classes i have at the moment, i don't mind changing them. I was thinking to create PlaceAction class and have a reference to a PlaceableItemSO there, passing it at instantiation. I'd have to explore this. Anyway id like to hear if it can be solved with some, any design that doesn't involve workarounds.
or id be satisfied with a reason why this downcast is not considered a workaround. I just don't have enough expertise to reason this
we gave you options
I don't like to downcast here either. I usually think it feels wrong because deriving classes exist to handle differences like this. In your current setup, thats really just the easiest way to go about it.
PlaceAction class and have a reference to a PlaceableItemSO there, passing it at instantiation
Assuming we arent talking about using SOs here anymore. "passing it" was the problem from the start. How do you plan to do this?
If PlaceableItem passes itself to PlaceAction: It currently doesn't store anything of type PlaceAction. You'd need to cast again.
I didn't understand your other suggestions really. This one: haven't used generics in a while, will look into this
Replied to wrong message, sorry
It wont really be compatible with serialization (my generics suggestion) in unity but its the best I can think of to inherit the list of actions but have the actions work with the specific item types.
Tbh id ditch the idea of functionality (ItemAction) as scriptable objects and implement functions directly on the items
Id have to check for a type of an item and then again i would have to check for/cast as a specific interface
Trying to think also how id use generics here but I don't really see how this would avoid the initial problem either honestly
Well a placeable item can have functions to do the placement functionality.
If say this is provided by the player, it can utilize this.
e.g. Item->Use(), PlaceableItem->Use()->StartPlacementMode()
I presume you want all items to be "usable" via a shared function/interface
Any item can have multiple actions, can be any number of them. I would have to pass a string as a parameter and have a switch statement or something which is ugly already
I switched to action as a class to prevent this in the first place
you cant magically share these actions between many item types AND get the item as the type without casting 😐
I dont think you should really avoid this. Realistically lets think of PlaceAction here. What if I passed in something that wasn't PlaceableItem? This should be an error. The two rely on each other heavily.
Maybe inside that Perform function, pass the UsableItem. PlaceAction should just cast and read the values
generics make it work as its essentially code gen so a version is made for each generic type used
If you don't want to cast at all, then PlaceableItem has to be the one doing the logic with size and sceneObject
the solution is to cast and just deal with it 😆
(UsableItemSO)item
then up to you to ensure the action is not given to the wrong item types
Hmm, true. i guess i don't care if i have actions separately. How would i map inputs to concrete functions?
How do you need it to work, is it a certain key to use some action?
Say when i hold a placeable item f to Place(), R to Rotate().
When i hold throwableitem f to ThrowOverhand(), Z to ThrowUnderhand()
🤣
Havent made something like this myself, (and dont really have time atm to think of a design), so it's a bit hard to suggest anything. Also itd matter if some throwable items could only be thrown overhand for example.
The first thing that comes to mind would be using a collection of Action and defining all the possible actions in each item type.
specifically System.Action, not to confuse with your ActionSO thing
Having an issue with GLTFast and UniTask. Currently doing this to load a bunch of GLB files asynchronously:
foreach (FileInfo fileInfo in filePaths)
{
GltfImport gltfImporter = new GltfImport(null, deferAgent);
var task = gltfImporter.Load($"file://{fileInfo.FullName}", settings).AsUniTask().ContinueWith(
async t => {
if (t)
{
//Do various onSuccessful things here
}
else
{
Debug.LogError($"Unable to load asset file://{fileInfo.FullName}");
}
}
);
tasks.Add(task);
}
await UniTask.WhenAll(tasks);
But I'm getting a null reference exception inside of .Load due to some malformed data in a GLB file. This means the entire task ceases to be, and it never gets to the ContinueWith condition, it just dies. I want to display information to the user about a broken file, but I don't know how I could. How would I gracefully handle essentially Try-Catching a task?
Perhaps move everything into a separate method:
public async UniTask LoadAsset(FileInfo fileInfo)
{
try
{
var gltfImporter = ...;
var t = await gltfImporter.Load(...);
// ...
}
catch (...)
{
// ...
}
}
In general you don't want to mix async/await with .ContinueWith.
I'll admit I don't know a lot about how to properly deal with Tasks and whatnot, but that was the suggested code from the GLTFast documentation, with an extra AsUniTask in there so I can us that instead of a normal system task
The "Tune loading performance" section
https://docs.unity3d.com/Packages/com.unity.cloud.gltfast@5.2/manual/ImportRuntime.html
Inside a UniTask like LoadAsset, you can await regular tasks just fine so you don't need to .AsUniTask() to convert it. .AsUniTask() is most of the time used when you already have a task, you don't need to change that task in any way (eg continuation and error handling), and you want to pass that task to somewhere that only accepts a UniTask.
If you do need to do more logic like continuation and error handling, it's much easier to just write async/await rather than .ContinueWith.
In your case what's failing isn't the task but the synchronous call of .Load, then you would need to do something like:
foreach (FileInfo fileInfo in filePaths)
{
try
{
var gltfImporter = ...;
var task = gltfImporter.Load(...).AsUniTask().ContinueWith(
// ...
);
tasks.Add(task);
}
catch
{
// ...
}
}
ok so i currently am in stencil buffer hell and i wanna do some things but am failing, how could i make it so that i instantiate the triangle at the very end of the black circle, and not the middle of it, like in the second image?
also, do intersection shaders properly work with stencil buffers?
Tasks when awaited re throw exceptions so they can be caught. If you adjust your code you can catch the load exception and still await all of the loads:
async UniTask LoadGLB(string name)
{
GltfImport gltfImporter = new GltfImport(null, deferAgent);
try
{
var glb = await gltfImporter.Load($"file://{name}", settings).AsUniTask();
//Do thing with successful load
}
catch (Exception e)
{
Debug.LogException(e);
}
}
foreach (FileInfo fileInfo in filePaths)
{
var task = LoadGLB(fileInfo.Fullname);
tasks.Add(task);
}
await UniTask.WhenAll(tasks);
making a local async function can be useful in situations like this!
Yeah basically what this is.
Also consider how you want to handle exceptions in relation to the other tasks. If one task fails, should the entire process be aborted, or should the other tasks still continue? If you want the entire process to be aborted, you also need to cancel the already started tasks.
I caught the individual load fails as it sounded like they want to try to load them all but not break the entire process
Tried to wrap the .Load section in a try-catch, and it didn't trip. The error came up on await UniTask.WhenAll(tasks) line
So it's not the call to Load that's causing it
Gonna try this now
It's like the exact same code as my first snippet, but yeah.
Its almost the same but i omitted the continuewith
anyway we both explained the same concept 👍
(I gave two snippets in case you missed it, the first one is the exact same code as yours)
Oh, sorry, I didn't really look at that one, I saw your suggestion to avoid the ContinueWith and went to go find why I was doing that and forgot to actually give that code a try
sorry to repeat the same stuff but hopefully its enough to get thing working
Yeah the second snippet is more so showing how the same logic can be written both ways (assuming the exception is in .Load which turned out to not be true), the first one is really the one you should be doing.
Okay, this one works and gives me an error message and lets me skip the failing file and let the user know which one broke
Thanks! One of these days I will actually understand what tasks do under the hood so I can figure out what to do when they go wrong
All you gotta know about this bit is that an exception thrown inside an async method is collected by the task and thrown again when it's awaited
A quick and dirty way to think is that async/await is a syntax sugar on top of .ContinueWith, so unless you have very good reasons not to, you should just use async/await everywhere and pretend .ContinueWith doesn't exist.
So you either catch it so it never hits the task, or you catch it up where you await any task above
magic state machine code gen and stuff all handled by the compiler 🙏
there are cases where ContinueWith can be useful, for example chaining with task.WhenAll.
But yeah you're not wrong
Hi. how can I get the angle of the bullet in relation to its forward direction in comparison to Up and Down vectors? Preferably a value between 0 and 1
float angle = Vector3.Angle(transform.forward, Vector3.up);?
Thanks. I have it returning an angle, but I can't get it to sign the angle. The values I get are identifcal whether pointed above or below the forward direction. I'm using this code:
Vector3.SignedAngle(transform.forward, Vector3.forward, Vector3.up);
I got the value I wanted with ```cs
Vector3.Cross(Vector3.forward, this.transform.forward).x
How performance intensive is raymarching in 3D? I have like a single cube renderer as bounds area for like 6-8 spheres that need sdf blending. It'll always be running.
anyone know networkmanager callback for on network manager spawn object?
Depends on the implementation and the hardware in use of course but something as simple as couple spheres is likely totally fine
Hello! I'm looking to offload some performance intensive tasks from my main calling stack, to reduce the load on my main thread. im looking into async programming and coroutines. i found this https://github.com/Cysharp/UniTask?tab=readme-ov-file#asyncenumerable-and-async-linq that says its a better form of tasks that can go into unity functions. My problem is, if i run everything async but still on the main thread, doesnt that still cause performance issues? the whole goal of async is to let multiple threads be able to handle the data no?
Conceptually, whether something happens synchronously is not necessarily related to whether it's processed by the main thread. For your needs, I expect you want to look into the job system + burst compiler
UniTask has RunOnThreadPool, or SwitchToThreadPool/SwitchToMainThread.
But yes depending on the type of task you are doing and the requirements, might be better to use job system + Burst if the goal is to speed things up (it would require some rewriting though).
If the goal isn't necessarily speeding things up but simply to not block main thread, then running the code on a background thread is the easiest and might not even need any code changes.
thats kinda the goal, its to prevent computation work from lagging the players fps right now. i can use parallelization if i need to, but for now its not really efficiency as it is player experience. i didnt know unitask had runonthreadpool mb, in the readme it says "always runs on main thread"
Async means that you don't execute the whole logic immediately, thus avoiding blocking the thread for that duration. It allows you to break up the logic into smaller pieces that don't take much time and executes these pieces one by one making breaks to let other logic/code run. Thus it takes more time to complete the async logic, but it doesn't bother(at least not as much as sync) other logic that could be more time sensitive.
This, even if it's not running on a separate thread, it doesn't mean that it's meaningless.
what causes your long frame times anyway?
Heightmap terrain editing, i delayed my lod, but still if i use like 1k-2k detail heightmap area for some precise editing, it can cause some problems in main thread. im only setting the heightmap for the area that actually get editted but still.
you can't speed that up by threading
Ahh, when you try to set the heightmaps of the terrain, its done / has to be done immediately / synchronously? i thought the lag may be caused by the large for loop that was running to setup the array, so was just going to make async to future proof.
you should profile that in detail, from what i understand, updating the terrain is fairly slow on the engine side, so if you are performing large-ish updates (whatever large is) you will get some spikes, so continuously updating is probably not a good idea
ahh, then i need to find an alternative terrain system for smaller areas of the map that offers accurate continious changes. thank you for the help
You need to profile
Making random solutions not based on actual profiling data might make it worse
personally i look at unity terrain as a read-optimized data-structure that is capable of quickly creating LOD meshes from huge datasets. Based on that i would not expect that writing to that structure is fast or can be made fast, as its a common trade off in optimization go for either read or write speed (not both)
I will profile, but if the terrain system is highly inefficient for what im trying to use it for, then its worth it to change no matter what the profiler says.
Whether the terrain is efficient or not is highly questionably and depends on your specific use case.
All of this would be clear if you profile
yes, i know it would be. my question was more so about how async works, not really about profiling.
Well, then you got your answers.
But perhaps it's worth stepping back a bit and looking at the whole picture.
I'm sorry for creating the Xy problem, thats on me. Let me reformat the question then. I want to be able to till ground by changing the height of the terrain underneath me. I'm currently trying to figure out how to make it in a way that both offers accurate changes, and doesnt impact the users fps at all while editting. The Async question was related, but i was more so confused about the goal of async, eg. why use async if you dont use a seperate thread, which was answered.
A smallish update on a few pixels only to the heightmap should not be an issue (personal experience in a tiny project with a normal size terrain of 1km size, 2k resolution and a first person camera, changing no more than 9 pixels at a time ), but that might not be true if the terrain is relatively small (10m) and has high resolution (2k) which would mean large parts of the terrain have to be regenerated for spatially small changes. its also likely that you have many chunks in LOD0 state depending on pixel error settings. You could try changing the pixel error and see if you get different results that still look acceptable.
i've been working on open world car game, and taking huge inspiration on one city. i extracted that city heightmap and applied it to terrain. currently im trying to also import roads but to no avail. i have GeoJSON file with all roads in that city but im stuck on how to do that, any help would be good thanks.
I don't know exactly how detailed the GeoJSON road data is. Is it just the center lines of the roads, or also the 3D shape?
If it's just the center lines, might wanna plug the data into some spline mesh generator
Some related stuff from a quick google: https://medium.com/@devlog/unity-3d-path-generation-from-2d-geojson-5f1076c70bfa
https://github.com/ElmarJ/GeoJsonCityBuilder
thanks
The unity splines package can produce geometry from a spline and the inbuilt line renderer may also be good enough
https://docs.unity3d.com/Packages/com.unity.splines@2.8/manual/index.html
thanks
Anyone here knows thing or two about roslyn analyzer and source generation? I literally had my first contact with it yesterday so I barely even know how it works.
I want to create analyzer that simply finds all unique generic usages of a specific class and then emit a static class with read only collection of qualified names off all unique generic arguments used for that class into a specific assembly (you could say I try to c++'ify my project). To make life easier I decided to limit searching to only FieldDeclarationSyntaxes for now, and I managed to write something that I think kinda works, but it creates this static class in every assembly and in that read only array it includes only types found in that exact assembly, so Im kinda stuck as I have no clue how to make it so it finds all generic usages in all assemblies first, and only when it finishes source generation for my specific assembly kicks in with all the information gathered.
I might be wrong, but I think this is just a limitation of source generators. The main use case is for filling in partial implementations, which can only be done within isolated assemblies. For optimization, the analyzers/generators are run in parallel.
with that parallel nature I had in mind an idea that each assembly gets somehow flagged with information about what generic usages it contains, but then I would need to use reflections to union them all into a single collection in my editor code, which isnt ideal, thus I was searching for alternative
but maybe someone has a better idea with their experience
to put it simply I have generic ScriptableObject type and I want to automate defining concrete types when such are in use, so if user defines a field somewhere public GenericSO<int> system ensures that there is a generated file that defines it in non-generic way to work with unitys serialization (Simply an empty class in its ow file like internal class GenericSOInt : GenericSO<int>{}).
I woulder if unity specifically makes this not be required for lists (and now unity events)
Is it not usable for other generic classes too? I forget.
I mention this as I remember unity events used to need this workaround but then it was changed
it works to some extend, but in case of ScritpableObjects you cant have a generic one, thats for sure
Ah right I failed to notice this, mb
even when you work around it and define manualy concrete definition as I mentioned, asset filtering works wierd in this case which bugs me XD When you have serialzied field of type lets say [SerializeField] private GenericSO<int> IntField and want to assign it in inspector, it cant diffirentiate closed types from each other so it will list you all variants, like ones derived from GenericSO<float> and so on
Do you also need to be able to reference this generated class in user code, or would they continue to just use GenericSO<int>?
no, the idea is to pretend like they dont exist, so I plan to create a separate assembly for generated closed types and keep these classes internal so user is allowed to use only generic definition
Then that opens up the possibility of using an IL post processor instead of a source generator. Instead of generating source code that gets included in the compilation, it runs after compilation and modifies or generates IL directly in the compiled assemblies.
And that workflow allows for scanning other assemblies as part of it.
The only problem is that it's an entirely undocumented part of Unity and only really intended for internal use. But it's used by many packages like Burst, Entities, and even some third party assets like Mirror networking.
Because it happens after compilation, none of its changes are visible to IDEs, hence my question before.
wait wait wait... I got kinda lost. Are you atalking about emiting these class definitions into IL or somehow just an information about generic usages? Because im interested in a latter one, as at the end of a day its not only about having a class definition, but to have it specificaly in a physical file so Unity can create meta file for it and for this thype to be associated with a guid for serialzation purpouses
Hmm, right, forgot about that part. I don't think source generators can do that either.
https://discussions.unity.com/t/in-39931-scriptable-objects-generated-by-a-source-generator-cant-be-created/918346
yeah thats why I try to use Roslyn mainly for finding generic usages, and then normaly in editor script create files and write to them
Are you using Roslyn mainly over performance concerns then, over using Reflection to find the types?
oh yeah definitely, I once did this kind of analysis with reflections and it was terrible XD
but I was young and stupid so I didnt even know about existance of such things like Rosylyn
(which was maybe half year ago)
How about letting the source generator generate an internal class containing all the generic definitions used in that given assembly, and then using Reflection in an editor script to find all those types in all the assemblies and generate the concrete classes in another assembly?
so I guess the only solution for me is to create some kind of manifest-like classes in every assembly that contains generic usages and then using reflections to union them in my editor script.
yeap its the only way ^
I have one other idea as well to try make it more optimized, as this reflections approach will still create some overhead
You could also use a IL post processor to find these instances, but Roslyn analyzers are well optimized for this task already.
If these internal classes could have something in common, like base type or class attribute, I could laverage the power of TypeCache in Unity which is absurdly fast for such things, but then the problem is that I would have to make sure that all these assemblies sees that base class or attribute
...which is a problem
it would need to be something that already exists and is provided by the engine, or is part of CoreLibrary but not used so often to avoid collecting other than these generated classes as much as possible
Since you only need to find one type in each assembly, and you can know its exact name, you can use Assembly.GetType. I don't know what it's performance is like, but it feels like it should be relatively fast, since it's an exact search.
yeah that will be fast but iterating over assemblies wont :/
hmmm you know what? You are right! Im overcomplicating things XD
that is actuyally the approach, I believe somewhere in CompilationPipeline unity gives easier access to cached assemblies with specific filters to avoid going through everything that is in domain and only iterate over user defined ones ond/or plugins
You can use the compilation reference to get all referenced assembly. https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.compilation.references?view=roslyn-dotnet-4.13.0
You can also use the compilation AssemblyName to only generated in the assembly you wants. https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.compilation.assemblyname?view=roslyn-dotnet-4.13.0
I suggest that you do not put your analyzer inside an Assembly Definition. From what I tested, I could not reference correctly the generated code same if it was supposed to be generated...
damn im struggling so much with the new urp
i dont get why the shader Lord.mat_effects doesnt really have a depth texture
void OnEnable() => RenderPipelineManager.endCameraRendering += ApplyEffects;
void OnDisable() => RenderPipelineManager.endCameraRendering -= ApplyEffects;
CommandBuffer cmd;
void ApplyEffects(ScriptableRenderContext context, Camera camera){
if (!camera.name.Contains("Soul(Clone)")) return;
if (camera.targetTexture == null) return;
if (Lord.mat_effects == null) return;
if(cmd == null){
cmd = new CommandBuffer { name = "ScenePostProcessing" };
}
cmd.SetGlobalTexture("_CameraDepthTexture", BuiltinRenderTextureType.Depth);
cmd.Blit(camera.targetTexture, Lord.soul.result, Lord.mat_effects, 0);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
raw_image.texture = Lord.soul.result;
}
!code
📃 Large Code Blocks
Use links to services like:
https://paste.mod.gg/, https://hastebin.skyra.pw/, https://paste.ofcode.org/, https://paste.myst.rs/, https://scriptbin.xyz/
📃 Inline Code
Surround code with three backquotes. Not quotation marks.
To format as C#, add cs to the first line:
```cs
// Your code here
```
Add a comment with a line number if there is an error message.
What is the appropriate chat for asking questions about accessibility options with unity??
So how can i get Unitys Terrain Tools Brush Size
As i kinda need it for my Auto Terrain Painter
nvm i got it
I'm starting to suspect that Unity has no accessibility function any more. The plugin for TTS and STT doesn't seem to have been updated in the last year, and appears to have only marginal functionality.
does anyone use Newtonsoft.Json here? I wrote custom serialization for SO's and getting an error Item must be instantiated using the ScriptableObject.CreateInstance method instead of new Item.. Here's the code:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string path = null;
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndObject)
break;
if ((string)reader.Value == "resourcePath")
{
reader.Read();
path = (string)reader.Value;
}
}
return Resources.Load(path, objectType);
}
I tried like ten different approaches including making a subclass of DefaultContractResolver and it still tried to use new()
why do they need to be scriptable objects if they come from json?
is this editor or runtime?
Well, where exactly that new is? I don't see it in the shared code. Besides, if it's just deserializing Json into SO, JsonUtility would do it just fine.
it's runtime. I'm currently just trying to save and load one scriptable object, but in the future I will need to serialize a list of them
the new() is default object ctor as I presume and I think Newtonsoft by default uses it while deserializing most data types
it's not anywhere in my code
Don't you see it in the callstack? Or code related to methods in the callstack?
yeah, I see it, but when I try to open it the script with related issue is empty
Even if it's not in your code, by seeing where and why it invokes it you can troubleshoot it.
also I dont need to serialialize a whole SO, just some sort of reference for now, maybe a GUID in the future
should be that now
Assign IDs to your SOs and serialize the IDs.
yeah, it could also work
it's not a problem to serialize it:
"allInventoryItems": {
"resourcePath": "Items/FashionMagazine"
},
the problem is with loading it
I think no matter if it's an ID, reference path or GUID it will lead to the same issue
When deserializing the id, assign the correct SO reference to wherever you need it.
Not sure what issue you're talking about
because even if I return an already existing SO (for testing purposes of course) it still doesn't "fully" use the ReadJson properly and gives the error:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return UnityEngine.Object.FindObjectOfType<SOLibrary>().Item;
}
throws:
Item must be instantiated using the ScriptableObject.CreateInstance method instead of new Item. UnityEngine.ScriptableObject:.ctor () Item:.ctor () (wrapper dynamic-method) object:lambda_method (System.Runtime.CompilerServices.Closure) Newtonsoft.Json.Serialization.JsonSerializerInternalReader:CreateNewObject (Newtonsoft.Json.JsonReader,Newtonsoft.Json.Serialization.JsonObjectContract,Newtonsoft.Json.Serialization.JsonProperty,Newtonsoft.Json.Serialization.JsonProperty,string,bool&) (at /root/repo/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:2247) Newtonsoft.Json.Serialization.JsonSerializerInternalReader:CreateObject (Newtonsoft.Json.JsonReader,System.Type,Newtonsoft.Json.Serialization.JsonContract,Newtonsoft.Json.Serialization.JsonProperty,Newtonsoft.Json.Serialization.JsonContainerContract,Newtonsoft.Json.Serialization.JsonProperty,object) (at /root/repo/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:479)
this throws the same error (even simpler version):
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ScriptableObject.CreateInstance(nameof(Item)) as Item;
}
unfortunately that's the script the error leads to:
Is that the whole callstack?
Possibly your vs code is not configured for unity correctly.
here's more:
Newtonsoft.Json.Linq.JToken:ToObject (System.Type,Newtonsoft.Json.JsonSerializer) (at /root/repo/Src/Newtonsoft.Json/Linq/JToken.cs:2084) Newtonsoft.Json.Linq.JToken:ToObject (System.Type) (at /root/repo/Src/Newtonsoft.Json/Linq/JToken.cs:2058) Newtonsoft.Json.Linq.JToken:ToObject<System.Collections.Generic.List1<Item>> () (at /root/repo/Src/Newtonsoft.Json/Linq/JToken.cs:1935)
SaveSystem.SaveData:Get<System.Collections.Generic.List1<Item>> (string,System.Collections.Generic.List1<Item>) (at Assets/Scripts/SaveSystem/SaveData.cs:21)
SaveSystem.SaveSlotFileHandler:Load<System.Collections.Generic.List1<Item>> (SaveSystem.SaveSlot,string,System.Collections.Generic.List1<Item>) (at Assets/Scripts/SaveSystem/SaveSlotFileHandler.cs:137)
SaveSystem.SaveSlotFileHandler:Load<System.Collections.Generic.List1<Item>> (SaveSystem.SaveSlot,SaveSystem.Savable1<System.Collections.Generic.List1<Item>>) (at Assets/Scripts/SaveSystem/SaveSlotFileHandler.cs:143) SaveSystem.SaveSlotExtensions:LoadFromFile<System.Collections.Generic.List1<Item>> (SaveSystem.SaveSlot,SaveSystem.Savable1<System.Collections.Generic.List1<Item>>) (at Assets/Scripts/SaveSystem/SaveSlotExtensions.cs:9)
SaveSystem.SaveSlotDataHandler:BootstrapLoadedForDataLoad (SaveSystem.SaveSlot) (at Assets/Scripts/SaveSystem/SaveSlotDataHandler.cs:99)
SaveSystem.SaveSlotDataHandler/<>c__DisplayClass12_0:<SceneLoadedForDataLoad>g__callback|0 (UnityEngine.SceneManagement.Scene,UnityEngine.SceneManagement.LoadSceneMode) (at Assets/Scripts/SaveSystem/SaveSlotDataHandler.cs:85)
UnityEngine.SceneManagement.SceneManager:Internal_SceneLoaded (UnityEngine.SceneManagement.Scene,UnityEngine.SceneManagement.LoadSceneMode)`
I can try to send it all as a file the discord won't let me otherwise
Hmm, all other files work correctly with errors
but I will look into it
It seems like you're serializing Item that has an SO field.
You should make sure that the field is not being serialized/deserialized
Sending !code correctly:
📃 Large Code Blocks
Use links to services like:
https://paste.mod.gg/, https://hastebin.skyra.pw/, https://paste.ofcode.org/, https://paste.myst.rs/, https://scriptbin.xyz/
📃 Inline Code
Surround code with three backquotes. Not quotation marks.
To format as C#, add cs to the first line:
```cs
// Your code here
```
Add a comment with a line number if there is an error message.
This would solve your issue:
<#archived-code-advanced message>
wait, I forgot that I was serializing a whole list of Item. This error should be better:
https://paste.ofcode.org/Xk4Re9Yyyp6T7vq5bqLDcB
just for a single Item
I'm not sure I understand. Could you explain a bit more?
From my understanding I want to serialize the Item, but with a custom serializer that will only save ID/reference path etc
There must be a way to tell the serializer what fields to ignore. Look it up in the documentation
it's this field:
private static readonly Savable<Item> _allInventoryItemsSavable = new(key: "allInventoryItems");
Is Item inheriting from an SO?
that goes to this:
public class Savable<T>
{
public string Key { get; set; }
public T Value { get; set; }
public T DefaultValue { get; set; }
public Savable(string key, T defaultValue = default)
{
Key = key;
DefaultValue = defaultValue;
}
public Savable<T> WithValue(T value)
{
Value = value;
return this;
}
public Savable<T> WithDefaultValue(T defaultValue)
{
DefaultValue = defaultValue;
return this;
}
}
yes
Well, then your custom serializer doesn't work
yeah, it doesn't fully
it serializes properly
but Newtonsoft somewhere still tries to use new() on the result even tho it has specific instructions not to do so
I think it just uses the default serializer.
it it did it wouldn't serialize as inteded I think. Just deserialization doesnt work
because this works:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var so = value as ScriptableObject;
writer.WriteStartObject();
writer.WritePropertyName("resourcePath");
writer.WriteValue(GetResourcePath(so));
writer.WriteEndObject();
}
Well, you'll need to share all the code relevant to the custom serializer
properly serialized SO here:
"allInventoryItems": {
"resourcePath": "Items/FashionMagazine"
},
using System;
using Newtonsoft.Json;
using UnityEngine;
using SaveSystem;
using UnityEditor;
public class ScriptableObjectConverter : JsonConverter, IAutoJsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(ScriptableObject).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var so = value as ScriptableObject;
writer.WriteStartObject();
writer.WritePropertyName("resourcePath");
writer.WriteValue(GetResourcePath(so));
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ScriptableObject.CreateInstance(nameof(Item));
}
private string GetResourcePath(ScriptableObject so)
{
if (so == null)
return null;
string assetPath = AssetDatabase.GetAssetPath(so);
int resourcesIndex = assetPath.IndexOf("/Resources/", StringComparison.OrdinalIgnoreCase);
if (resourcesIndex >= 0)
{
string relativePath = assetPath[(resourcesIndex + "/Resources/".Length)..];
if (relativePath.EndsWith(".asset"))
relativePath = relativePath[..^".asset".Length];
return relativePath;
}
return null;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace SaveSystem
{
public static class ConvertersLibrary
{
private static List<JsonConverter> _allConverters;
public static List<JsonConverter> AllConverters
{
get
{
_allConverters ??= GetAllConverters();
return _allConverters;
}
}
private static List<JsonConverter> GetAllConverters()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(t => typeof(JsonConverter).IsAssignableFrom(t) &&
!t.IsAbstract &&
typeof(IAutoJsonConverter).IsAssignableFrom(t))
.Select(t => (JsonConverter)Activator.CreateInstance(t))
.ToList();
}
}
}
and used in other script:
private static readonly JsonSerializerSettings JsonSettings = new()
{
Formatting = Formatting.Indented,
Converters = ConvertersLibrary.AllConverters,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
Where do you call the deserialization?
in SaveDataHandler.cs:
public static T Load<T>(SaveSlot saveSlot, string key, T defaultValue = default)
{
return saveSlot.Get(key, defaultValue) ?? defaultValue;
}
SaveData.cs:
using System;
using System.Collections.Generic;
namespace SaveSystem
{
public abstract class SaveData
{
public Dictionary<string, object> Data { get; private set; } = new();
public virtual void Set<T>(string key, T value)
{
Data[key] = value;
}
public virtual T Get<T>(string key, T defaultValue = default)
{
if (!Data.TryGetValue(key, out object rawValue)) return defaultValue;
try
{
return rawValue is Newtonsoft.Json.Linq.JToken token
? token.ToObject<T>()
: (T)Convert.ChangeType(rawValue, typeof(T));
}
catch
{
return defaultValue;
}
}
}
}
This seems to be quite different to what they're doing in the example in the docs:
https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm
which part do you mean? I have a lot of custom code here
The deserialization part
What's Conver.ChangeType?
Or is that not the deserialization?
I can't see where you actually deserialized the json.
the token.ToObject<T> handles deserialization here
that's from System and it just convers the type so I think it should cause the problem
but .ToObject<T> might now that I think about it
Well, I'm not sure that uses custom serializer.
I'd follow the documentation
also here's deserializing the SaveSlot itself:
public static SaveSlot GetSaveSlotFromFile(int index)
{
string path = GetSaveSlotPath(index);
if (!File.Exists(path)) return null;
try
{
string json = File.ReadAllText(path);
return (JsonConvert.DeserializeObject<SaveSlot>(json, JsonSettings) ?? new SaveSlot()).WithIndex(index);
}
catch (Exception ex)
{
Debug.LogError($"Failed to load save slot {index}: {ex.Message}");
return new SaveSlot();
}
}
Will look into it
damn it works!
thanks a ton for your help with troubleshooting
it never used the settings for deserialization before like you said
just provided them like this:
public virtual T Get<T>(string key, JsonSerializer jsonSerializer, T defaultValue = default)
{
if (!Data.TryGetValue(key, out object rawValue)) return defaultValue;
try
{
return rawValue is Newtonsoft.Json.Linq.JToken token
? token.ToObject<T>(jsonSerializer)
: (T)Convert.ChangeType(rawValue, typeof(T));
}
catch
{
return defaultValue;
}
}
so .ToObject<T> just needed a jsonSerializer
Guys, does the backend service with C# modules support data persistence in memory? If so, how long does it stay active and what would make it clear this cache? Is there any documentation?
founded!
Does anyone here know anything about Unity capability with TTS or STT?
I imagine you'd use some open source models with sentis these days.
Otherwise, I guess there's this:
https://docs.unity.com/ugs/en-us/manual/vivox-unity/manual/Unity/developer-guide/text-to-speech/tts-overview
Is there an easy way to modify a single script in a package without having to copy the entire package
Not really.
I would try hard to avoid it if possible.
yeah, but unity got bugs 😔
[Netcode] Cannot start Host while an instance is already running
UnityEngine.Debug:LogWarning (object)
TitleScreenManager:StartNetworkAsHost () (at Assets/All/Skrypty/Title Screen/TitleScreenManager.cs:54)
bruh i dont know what to do
the line at titlescreen:54 is
public void StartNetworkAsHost() //blad
{
NetworkManager.Singleton.StartHost();
}
and there there isn't any error
also
i didn't noticed this error at first and now im struggling to fix it
please help😖🙏🏻
any1?
Are you calling NetworkManager.Singleton.StartHost() or StartNetworkAsHost() from more than one place? Seems like the singleton checker is just warning you the latest call is an extra.
If you don’t have the installer for those you are likely in breach of some non-disclosure or non-distribution agreement. Generally you only get those if you also have access to a Xbox dev kit.
working on a vr game rn, and im trying to recreate the movement in orion drift so i have something to build off of. how would i implement the carving? carving is a way of making sharp turns while keeping momentum, by kinda rotating around your hand. this is my script atm, no carving yet
Perhaps you should attempt it first
Share !code correctly:
📃 Large Code Blocks
Use links to services like:
https://paste.mod.gg/, https://hastebin.skyra.pw/, https://paste.ofcode.org/, https://paste.myst.rs/, https://scriptbin.xyz/
📃 Inline Code
Surround code with three backquotes. Not quotation marks.
To format as C#, add cs to the first line:
```cs
// Your code here
```
Add a comment with a line number if there is an error message.
wow thanks for your helpful advice
Hi I'm having some problem with my entity bot object not showing up visually.
public class NavAgentAuthoring : MonoBehaviour
{
[SerializeField] private Transform targetTransform;
[SerializeField] private float moveSpeed;
[Header("Rendering")]
[SerializeField] private Mesh mesh;
[SerializeField] private Material material;
private class AuthoringBaker : Baker<NavAgentAuthoring>
{
public override void Bake(NavAgentAuthoring authoring)
{
Entity authoringEntity = GetEntity(TransformUsageFlags.Dynamic | TransformUsageFlags.Renderable);
AddComponent(authoringEntity, new NavAgentComponent
{
targetEntity = GetEntity(authoring.targetTransform, TransformUsageFlags.Dynamic | TransformUsageFlags.Renderable),
moveSpeed = authoring.moveSpeed
});
AddBuffer<WaypointBuffer>(authoringEntity);
}
}
}
Here's my baking code, placed on the bot gameobject itself which is a child in a subscene gameobject in the scene.
Am I doing anything wrong?
I would move this to #1062393052863414313
alright
I want an opinion, for a PF algorithm you guys think that it is better to run ASYNC with everything in the code or have it's own loop for each path that should be created?
You'll need to explain what you mean by PF first.
pathfinding presumably. But I think the question is too vague. Different games have different requirements for pathfinding.
Some games can precompute all the pathfinding up front. Some need to do it dynamically.
have anybody seen this error during building?
it just stuck in here each time I try to make a build
already tried to delete Libraries folder
ventilation is up like if it would be doing something...
Check the task manager. What resources does it use?
I already stopped it from task manager
"Version Control: Cannot check out files in offline mode"
this is in the errorlog
can this be really a reason for making the build to stuck?
Theoretically, yes.
can't I just "disable" it for now?
Where did you save the build?
well, not into the cloned repo
Theoretically, there's nothing that should be checked out during the build.
Does it not point to any files?
Are there any other messages around that one?
nope, only this thing two times
there were other errors I already fixed
Are you using unity vcs?
nope, p4
Ok, that might explain. Do you have it configured correctly to ignore unrelated files?
what unrelated files? related to what?
Make sure none of the temp/build related files are added to the depot
Related to build
Unrelated to version control
well, by default I didn't set that, but its not even in the workspace
so I'm making the build into outside of the workspace
You should only version assets, source code, meta files and a few config files. Everything else needs to be excluded.
Something is in the workspace.
Like temp files or library.
Make sure these are ignored.
well, I guess some stuff is setted up into something like gitignore
which was already in the project
by others
well, isn't it working like Git? in there you have a .gitignore you can add to the repo
and its pulled for everyone
and thats all
Gitignore is not used by p4
I guess p4 has something similar as well
I never stated that
Yes. You'll need to configure it.
but why me? I mean if its a project used by million team members
then its probably already setted
Well, that's what you're supposed to investigate.
Others could possibly have local ignore file that is not in the depot
I mean others are building probably daily from the same sources
Or they have the workspace configured to not set files to read only
Anyways, something is wrong with your environment and you should figure it out.
well, I'm not even online
not even connecting to the version control
That might be the issue
Well, isn't that the issue? According to the log
Are you using the unity plugin?
that's not an issue, that's expected, because I work from home now
and I didn't want to connect to the VC now
for Git, this was never an issue
It shouldn't try to check out files though
Then configure the workspace such that it doesn't need to checkout stuff
you could be offline whenever you wanted and you could use the project as it is
with Git
Yes, git is distributed. P4 is centralized
Then use git lol
I mean, what's the point complaining to us?
Perforce requires checking out files before modifying
I'm not complaining, lol
I just wanted to figure out if I could make a build without connecting to P4 or not
that's all
Then configure it that way
I somewhat thought building doesn't modify project files at all
at least not the ones inside Assets folder
It doesn't, but it seems like you don't have an ignore file, so it monitors temp and other files as well, which do get modified during the build. Make sense?
then I guess it would constantly appear in the changelists (when I'm online)
but its never there
Because it can't check them out
doesn't make sense at all
What about the build folder?
those folders/files are never in the changelists
Files only appear in the pending changes when you check them out
Or reconcile offline work
that was also never there
You should really start from looking at the depot. See what files are added to version control. Perhaps some temp files are added. If so, then whoever created and manages the depot are just dummies
found the .p4ignore file
can't see the depot, I'm offline
anyway, I have found the p4ignore file
Ok, make sure that it's in the correct place and contains the expected paths
can I use this the same way as .gitignore? so adding the path where the file was P4 couldn't check out offline, making the build, and when I go back where I can connect to P4, I can remove that line from p4ignore?
would this work?
Yes.
thanks
Though, thinking about it, if the ignore file was not in there originally, it might not help.
it was there...
Then what happened to it?🤔
well, the error message was this:
Version Control: Cannot check out files in offline mode
Assets/StreamingAssets/addressable_keys.json
and the Assets/StreamingAssets is in the p4ignore or whatever it is called
yes, p4ignore
but the thing is that
only specific file types were mentioned in the p4ignore inside that folder
Ok, so there was more info that you didn't reveal... You could have saved us a lot of time...