#archived-code-advanced
1 messages ยท Page 122 of 1
Well, that could potentially be the cause.
A lot != Everywhere
that's true. lots of sync code but async where useful
But perhaps it's not the cause. Take a screenshot of the whole profiler
It's weird that the player loop doesn't show anything.
though... I think I fixed it a bit..? a lot of the functions use NativeArrays, and I had them all using Allocator.Persistent
after changing them to Allocator.Temp though, seems like something broke along the way
Why are you using native arrays?
Some of the things I'm using only accept native arrays, such as the indirect mesh renderers
here's a screenshot after the changes I just mentioned
I am so far out of my depth here I swear lmao
im more confused with each message what you are actually doing ๐
async will make using the profiler hard so use Stopwatches to time specific things
I'm gonna have to pause work for tonight but I'll figure out how stopwatches work in the morning and get back to y'all
the overall idea of what I'm trying to do is parse a 600k point dataset (that has arbitrary XY coordinates) into a landscape where each datapoint is represented as a plant. To make that work logistically, the plan so far has been to procedurally generate the terrain chunk by chunk, with each terrain chunk having it's own compute shader that renders only the plants that fall within the coordinate range of that specific chunk
I already know that it isn't the mesh generation that's super performance costly, at least not with how it's configured currently
What is this set to? It's not the default option, is it?
Your profiler hierarchy is weird atm
currently set to inverted hierarchy, this is how it is with the normal hierarchy
Ok, that's way better. We can now see that GC is the main culprit
are you starting thousands or millions of tasks all at once...?
Are you getting errors in the console? It seems like stack traces are one of the main sources of gc
Or just logging a lot of messages
Likely yeah, like I said, almost every function right now is UniTask
both, logging from debug and errors from the indirect mesh renderers before their coordinate nativearrays are done processing
Fix all these and profile again
Reducing logs to not print every frame would help too
I'm not entirely sure how to fix that currently. I guess I'd need to start it with the indirect mesh renderer component on each chunk disabled by default and enabled once it has a nativearray of coordinates, but I can't figure out the logistics how to actually do that
This is the function responsible for when that render actually happens, for context ```C#
public async UniTaskVoid GetChunkPlantData()
{
while (parq.kdTree == null)
{
await UniTask.Yield();
}
Vector2 rangeMin = await parq.GetCoordinateBoundMin(chunkIndex, parq.plantMapSampleScale);
Vector2 rangeMax = await parq.GetCoordinateBoundMax(chunkIndex, parq.plantMapSampleScale);
df = await parq.GetTerrainChunkDataFrame(rangeMin, rangeMax);
if (df.Rows.Count >= 1)
{
rawCoordinates = await parq.GetCoordinatesAsNativeArray(df);
rawCoordinates = await parq.ScaleCoordinateArray(chunkIndex, rawCoordinates, rangeMin, rangeMax, chunkScale);
rawCoordinates = await GetPlantHeights(rawCoordinates);
kdTree = await MakeChunkKDTree(rawCoordinates);
coordinatesForRendering = await DoubleInstanceCount(rawCoordinates);
UniTask.Void(StartRender);
}
}```
I don't even know what the error is and where it is thrown, not to mention what you're trying to do.
So kinda difficult to help you there.
yeah fair lol
I think I might've figured that out just now though thankfully, realized that I should be checking if df exists in the Update loop as well as within this function
Yeah, there we go. For some reason the 1.3 million alloc calls are back though
at least the indirect mesh renderers are working again
Yep,this is likely due to you using async everywhere.
And possibly, allocating garbage in them as well(which might be hidden by the async implementation). I'd start from reverting all the async methods back to normal methods.
UniTask shouldn't be a huge allocator
Just properly profile it and you'll see what's allocating
Yeah, but it probably hides the real allocations
There's almost no chance UniTask is allocating 2.8GB
According to the screenshot, there are 1.3 million calls to GC.Alloc
I bet the native arrays that they mentioned earlier are the real cause.
That's very suspicious. Do a deep profile to see what exactly is allocating.
I don't think native arrays show up as part of that.
Are you looping over Mesh data?
Perhaps a loop over vertices
I'm just guessing, but if so, calling mesh.vertices.Length or similar is allocating the entirety of the array just to read the length for each iteration of a loop
When unity naming conventions for properties bite you...
More so that it shouldn't have been a property in a first place. It being a method like GetVertices() would make it very clear that for (var i = 0; i < mesh.GetVertices().Length; i++) is not a good idea. Or other properties like .material creates a copy that you need to destroy. All the hidden footguns ๐ข
I don't think so, but if I am, it would be when the meshes are being generated, and that happens pretty quickly
Do a deep profile and see what's allocating.
Well, allocating is not as heavy as collecting the garbage.
And that can happen anywhere where the GC pleases.
wym by deep profile?
it's an option in the profiler
it's equivalent to slapping profiler markers on EVERYTHING
oh yeah, that'd be awful
O(no)
note that this will make things run a lot slower
If you have a vague idea of where the allocations are, manually inserting profiler markers will be a lot nicer
I'll try that tomorrow, I'm off the clock for now
High perf + Async-await doesn't get along too well, that's not the point of the current async-await.
just saying, thread switching ain't free
It depends. Performance is a complex topic that has place for many things, including async await.
Sure, there might be a solution that is more performant, but you also have to balance out the costs vs the actual gains.
the current state async-await ain't built with perf in mind at all, they introduce a sum amount of overhead on hotpaths.
that's one of the reasons why they come up with async2 https://github.com/dotnet/runtimelab/tree/feature/async2-experiment
async + perf will hardly, unlikely be a perf
note, that I'm not disagreeing with you here
Again, it depends on the use case. It would be totally fine for offloading file reading/writing or some other work to a background thread. Of course, you wouldn't use it for computations(unless you're fine with them taking some time).
Which is arguably part of game performance, because if you were to do it on the main thread, it would kill it.
On the topic of threading, how does everyone here run their jobs if you want to start a job at the beginning of the frame, let other stuff run, then only force complete by the end of the frame? Seems like something that should be simple but the examples I've seen so far add tons of boilerplate vs. just doing all the job management in a single method like Update()
what does "force complete" mean, block the main thread until the job/thread is done?
JobHandle.Complete(); yeah.
oh right. well i would not use this because if it takes longer than your target frame rate time its gonna look shit.
Id either try to await the completion/have some code to run on completion
Yeah it doesn't, I've got it all in Update() at the moment and it works fine, but I don't need the results til the end of the frame so trying to optimize further
Well in reality you are just waiting for it to be ready at some point during some frame and then using the results which is a good way to do it.
Well, there's late update.
Or you could wait till the next frame.
there is no guarantee the thread/job gets executed soon enough but if the work is small it probably will. But then the question arises as to why use a job/thread if its that quick ๐ค
Hi everyone, I'm working on a pattern check in my chunk genration system where it iterates over a cell and its neighbours and determins if it fits specific patterns.
I "could" have 4096 cells in a chunk and virtually an unlimited amount of patterns to check (though more realistically it will be closer to ~16 to ~64 cells, and ~20 patterns). This check will be done once on chunk generation, what I was wondering is this:
How would I best go about converting this to a job, right now I have a ParallelFor job that takes in the cell coordinate, its neighbouring cells and then iterates over all patterns checking which fit given the current data.
This works great for parallelising the pattern / structure checks, but it doesn't solve the other issue that I also need to perform this check for many other cells. This intern basically turns into a nested for loop.
foreach (cell in cellList)
{
neighbourData = get the current cells neighbours
foreach (pattern in patternList)
{
do the pattern check with neighbourData.
}
}
The current implemententation is this:
foreach (cell in cellList)
{
neighbourData = get the current cells neighbours
IParallelForJob check all patterns....
Output first pattern that fits....
}
So specifically, my question involves how best to work with nested loops, given that jobs cannot be called from within other jobs. I know I could create a large dataset and then pass it all in as one massive loop but that setup time would take more time then its worth parallelising it. Any thoughts on the subject would be great!
To let it run in parallel with the main thread. Even if it's just 4 ms, you don't want your main thread to get +4 ms when you can avoid it.
yea its gonna depend on the actual stuff you want to do. If you win in terms of time spent on the main thread is probably worth it ๐
Well, one thing you could do is have the data always in a form that is ready for a job.
Other than that, maybe your approach is fine. Is there any actual issue with it?
The main issue is that I want to scale this up, right now it works but has some performance dips, that said it works with only a couple of pattern checks in very controlled enviroments. I want to be able to have this system be much more in depth and for that I need to be able to get rid of the main cause of the slow down.
The main reason I cannot have the data always in a form that is ready for this is because it may need information from chunks surrounding itself. Though with that said, I could pass in the chunk data from those.
Thank you, I may give that a try, and format the loop so I don't actually need to pass in the neighbouring data.
Should probably profile your setup to identify bottlenecks. And then think how to optimize them.
Having a fun one. _currentSpell is throwing a missing reference exception. It's an interface, but the underlying type inherits MonoBehaviour.
This is called during an animation callback.
Also attempted this to get the proper Object lifetime check but that either isn't the issue, or it doesn't work that way
Are you sure the problem is with _currentSpell and not with aimTarget being unassigned?
since it's an interface you can't rely on the == check
Yep. AimTarget is never changed.
Nothing in that line can throw a MissingReferenceException, except for aimTarget.position if aimTarget is a serialized field that is unassigned.
Is the exception coming from inside EndCast?
so you need to do this:
if (_currentSpell is not UnityEngine.Object uo || uo != null) {
}```
oh yeah which line is throwing it btw
yeah ok so _currentSpell was destroyed
this should sort you out
I often add a gameobject get property to interfaces for this purpose (if i know its for component use only)
is annoying how unity do their native object destroy checking via Equals though :/
UnityEngine.Object.IsObjectDestroyed(UnityEngine.Object o) and similar would have been lovely.
Yeah, seems to work. Thanks
Hello i have a game manager for a dice game that controls the flow of the game, once the dice have stopped moving (meaning they landed) i trigger a dotween animation that sends an event when its finished so that the game logic can continue (let player roll again) I just wanted to ask if this is the best way of handling the animation or if theres a better way
private void Start()
{
diceAnimator.OnMoveDiceToCamAnimationComplete += DiceAnimator_OnMoveDiceToCamAnimationComplete;
diceAnimator.OnMoveSingleDiceToCam +=
DiceAnimator_OnMoveSingleDiceToCam;
}
private void DiceAnimator_OnMoveSingleDiceToCam(object sender, DiceAnimator.OnMoveSingleDiceToCamArgs e)
{
if (playerDice.Contains(e.dice))
{
e.dice.GetLastLandedFace().TriggerFaceAction();
playerScore += e.dice.GetLastLandedFace().GetValue();
}
else
computerScore += e.dice.GetLastLandedFace().GetValue();
}
private void DiceAnimator_OnMoveDiceToCamAnimationComplete(object sender, EventArgs e)
{
gameState = GameState.WaitingForPlayerInput;
DetermineWinner();
}
private void Update()
{
if (gameState == GameState.WaitingForPlayerInput && Input.GetKeyDown(KeyCode.Space))
{
RollDice();
}
}
private void RollDice()
{
foreach (Dice dice in playerDice.Concat(computerDice))
{
dice.UnlockRigidbody();
dice.Roll();
}
}
private void OnDiceStopped(object sender, Dice.OnDiceStopRollingArgs e)
{
diceStoppedCount++;
if (diceStoppedCount >= playerDice.Count + computerDice.Count)
StartDiceAnimation();
}
private void StartDiceAnimation()
{
gameState = GameState.AnimatingDice;
diceAnimator.StartMoveDiceToCamAnimation(playerDice, computerDice);
}```
sounds fine to me. If it's a linear sequence then there's not much you can do wrong
personally I just calculate the animation time beforehand and await that duration instead of relying on the animator, but if this works it works
Ok, I'm about to off myself. Memory issues are back. Context: I've got a (finished) webgl product that I've built in release mode which (often-ish) crashes with out of memory errors and no useful information (it's a javascript stack trace and a bunch of unnamed function pointers in my code).
In dev mode, I cannot make it crash.
I've updated to the latest 6000 unity build since there was a note in a recent release about a bugfix potentially related to this: https://unity.com/releases/editor/whats-new/6000.0.30#notes
- Web: Fixed WebGL errors when heap is larger than 2 GB. (UUM-85702)
I have no issues with a windows build and editor play. I started down the memory profiler, but I'm not convinced this is a memory issue since the dev build works just fine.. it's only the brotli compressed build that's having issues.
Looking for guidance. I have two links handy if anyone wants to try this out on their own (itch.io).
It does really seem like a out of memory though. Do you know what are your constraint ? (Memory limit)
I do have the chunk of code where it seems to be failing - it's some pathfinding code, but it works and doesn't soak memory in the editor, so I'm not sure it's the active culprit - but just rather a part of code where allocations need to happen.
2gb memory limit
(the game does have quite a few models, animations, sounds, textures, etc - it uses a lot "normally")
And how close are you from this limit ?
Memory varies a lot, sometimes you need a good buffer you prevent crashes.
HexPoint.TryGetPath() is my code
but the actual failure is just on adding a member to a list - not even a big list, but I'm exploring it just to make sure
Yeah, with OOM it is kinda hard to know if it is the actual code the issue.
But you should be able to see it growth.
Also, I've never developed on WebGL, but it seem that the garbage collector behavior varies in the web compare to the desktop. The situation describe could potentially be something you see in your Pathfinding algorithm.
that page has been up on my screen for the last week ๐
You could try to put manually more pressure on the memory to see if you can make it crash in a development build.
But again, it is strange that you are not seeing any change in memory.
There must be a way to output a crash dump and also debug symbols(even in a prod build). If you have the two, you could open it in VS and investigate the callstack/variable values.
what you see in the screenshot is all i got.. the debug symbols are in it so I have a rough stack trace but... it's just failing on a list.add
I've even just added this:
and the "oops" message is never seen
(that's the only .add() call in the method)
well we can see in the stack the list tries to change its capacity and it causes the crash
remember a list can resize up or down and must relocate each time
yeah... I mean.. I suspect there's a bug here in my pathfinding code but .. it's so odd that there's no spike in memory on my machine, and the method works just fine
The last time I had to investigate a memory crash that was not showing in profiler (because it was native memory), I had to try to disable each feature one by one to see which one was responsible. But I knew it was a memory leak though.
How much pressure you are putting on the memory with the pathfinding algorithm in a single frame ?
could be the issue with webgl where GC cannot happen mid frame and the constant use of pathfinding and temp lists fucks it
lemme see if I can tell.. I don't have the windows module and memory profiling package on this version of unity but I can get it
like, there's a lot of List.Add() in that code - but it's "normal" (ie, pathfinding needs to enumerate each hex in the path)
code like this for 15 units is over 1000 calls
but like, it's fine
you could replace the list with a static native list with a large capacity? something to prevent constant reallocation on the heap
each unit is doing what it's supposed to - like, their logic is "find the closest good guy" which means it has to pathfind to every one of 5 good guys (times 15 bad guys)
It could quickly become a lot of memory if it is not freed in the frame.
i could, yeah.. i mean, that would save several thousand add() (and check for capacities) beforehand but.. this still should be small .. like 10-20kb
not 2gb
lemme just add a quick static counter to check
You are busting by 2g ?
Because, sometimes you really are closer to the actual limit. I flirted with the upper bound of memory for the switch a lot.
(Also, logs potentially can add GC alloc)
1100 adds in the frame (but there should be adequate time to GC)
there's no logging on the server production build
what is your memory profiler saying anway?
I have to reinstall it (I updated unity today) - i don't have the package in the project atm
remember its at the END of the frame when GC can happen for webgl
it cant happen whenever
hm, ok, that's useful.. although these adds are for very small structs
public struct HexPoint : IEquatable<HexPoint>
{
public readonly int X { get; }
public readonly int Y { get; }
}
but the list resizing will move to a new array and the old array wont get deleted
essentially just that
are you just guessing where the problem is or do you know this list is the problem?
oh also those 1100 adds aren't in one frame - that's over like 10 seconds
I'm just guessing but I have a stack trace in this method that says the add is where the malloc fails
I can paste the entire pathfinding code but .. it's not light reading :p
it is where it crashes consistently so.. at least that's progress
yes, that is likely, because its a very dynamic point in the code, but you likely have a leak someplace else
not even a leak, maybe you just have a lot of memory usage by accident
maybe a single native shell of a texture your're keeping around
ok memory profiler back in the project.. I'm not an expert with this tool - do I want a snapshot before/after the incident? or is there a way to record a few frames with it
or a copy of a vertex array
You want to snapshot at two distinct point in the same scenario.
this pathfinding code has a lot of recursion in it - i honestly wouldn't be surprised if it's temporarily using a huge bite of memory, which would be a problem, if not the problem
you basically want to figure out where your memory jumps or grows unexpectedly, and where your memory actually goes
sounds reasonable
Usually, it is kinda trivial to remove recursive in an algorithm.
might be an idea to remove the recursion or make it tail recursive
If you ever doubt it is the issue.
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
happy to have you take a peek ๐
this is my static hexpoint class - it just contains x and y, with a whole host of utility methods
the method in question is TryGetPath down near the bottom
A* pathfinding for hex grids.. so.. yeah, it's a bit dense but .. hopefully? it's readable
i kinda hate the syntax highlighting on pastebin.com - lemme know if you want to read it and prefer another site's styling
I'm not sure I see the recursive though
yeah I don't either.. ha.. I thought it was. I guess it's just a while loop
you should be able to figure out any memory issues in this code with the (memory) profiler
I'm looking over the snapshot now.. i couldn't get it close enough to the "event" so I'm trying again
here's the baseline though:
I presume the list add that caused the crash sent earlier was when doing the walk back. You should give a size to the path list so its at a good capacity to start.
Also, you captured the editor
I can't get it to crash in editor - only for production builds in the browser (since there's 2 gb heap limits in the browser, i imagine)
yea cus anywhere else it will GC whenever it wants
I checked it above - it's not adding too many items to the list.. 1100 over 10 seconds of gameplay
I know, but Editor Memory Capture are terrible to distinguish correctly what is happening.
how do i capture memory snapshots in browser builds? I wasn't aware that was even possible
i couldn't get the crash in a standalone build
(I can't even get the crash in dev builds)
dev builds on web gl, to be clear
No need to make it crash, just to see if you can spot something growing.
okay you read the unity webgl memory page right? webgl has the big limitation of no GC during managed code execution. Meaning if you do lots of pathfinding one after another, all those lists and list reallocations are still eating memory...
so again when you go to pathfind and have your list grow and grow... BAM crash
yeah but i mean, only only allocating like... 20? 30? adds per frame, nothing unreasonable
but you dont give your lists a starting size so they may re allocate a few times
even if it were 1000 adds per frame (with the struct with two ints) that seems like it should be .. fine?
fair, I mean, I can add that (and it's a good idea) but .. I'm not sure it's the issue
I see a big grid and i dont know how many pathfinding operations you perform at once but I think its a potential cause.
snapshot comparison in editor wasn't insightful
If the issue is heavy heap allocation before gc it will never happen on other platforms
Yeah but the pathfinding should be reasonable - it's A* so it's doing manhattan distance, etc - I can add some debugging/logging to it, but it's pretty stable..
Lemme at least start with this - making some cached and presized lists and see if it still crashes in the same place
i'll report back in .. 15 minutes :p
Its good practice anyway to make a list with a smart capacity. e.g.:
List<int> myList = new(10);
for(int i = 0; i < 10; i++)
{
myList.Add(i);
}
we know we need space for 10 elements so we start at this size and avoid a wasteful list resize (where a new array is allocated and the contents is moved)
yeah i'm combing through my hexpoint class and finding every new() and presizing to 20 - which is pretty much the upper bounds on a path in my game
but the pathfinding i'll probably use... 50
The lovely ideal way would be you share 1 list over many executions like you can do with physics overlaps (the no alloc versions)
yeah, agreed, although that would be a pretty big change (i'd have to change the api surface so the caller could cache a list)
but i can do that if this isn't helpful
do what you said first so you dont go doing lots of work for no benefit ๐
public static int GetPathCost(this List<TerrainType> path) => path.Sum(x => x.GetMoveCost());
does this alloc?
an enumerator and delegate are allocated
public static class TerrainBehaviourExtension
{
public static int GetMoveCost(this TerrainType terrain)
{
return terrain switch
{
TerrainType.Normal => 1,
TerrainType.Difficult => 2,
TerrainType.Shrouded => 1,
TerrainType.Impassable => TerrainBehaviour.Infinite,
TerrainType.Hazardous => 1,
TerrainType.NoLineOfSight => 1,
_ => throw new NotImplementedException(),
};
}
}
(that's the getmovecost method - just a lookup extension)
Linq often can (but often has specific handling for lists)
that might be a problem... I imagine that GetPathCost() is being called hundreds or thousands of times per frame in the pathfinding
since my nodes aren't all 1 "unit"
id avoid all linq with this project ๐
perhaps, but it's just so damn convenient
i suppose i can also optimize this since if ANY tile is impassable the entire path is infinite cost
haha too bad for you, best to do it yourself with a for loop
/// <summary>
/// Path cost for a list of terrain types.
/// </summary>
public static int GetPathCost(this List<TerrainType> path)
{
int cost = 0;
int tileCost = 0;
foreach (TerrainType t in path)
{
tileCost = t.GetMoveCost();
if (tileCost == TerrainBehaviour.Infinite)
{
return TerrainBehaviour.Infinite;
}
cost += tileCost;
}
return cost;
}
foreach ok? or does that allocate an iterator that I don't need
like, i still need an iterator to get the length, don't i?
public static int GetPathCost(this List<TerrainType> path)
{
int cost = 0;
int tileCost = 0;
int pathLength = path.Count;
for (int i = 0; i < pathLength; i++)
{
tileCost = t.GetMoveCost();
if (tileCost == TerrainBehaviour.Infinite)
{
return TerrainBehaviour.Infinite;
}
cost += tileCost;
}
return cost;
}
or is this meaningfully better
oops syntax error - path[i] instead of t but you know what i mean
on new c# id trust foreach on a list wont use the enumerator ๐ค
tbh i really don't know since this is run through mono/il2cpp anyway, right? like, internally it should end up as a normal for loop without all the c# bounds checking and stuff? or will that bound checking get embedded into the loop?
optimization is black magic ๐ช ๐
I'll use the second approach and pray.
mono is old so even though its converted to cpp if the produced IL is shit then we get shit cpp
OK added all the new presizing and am doing a production build.. will let you know in 15 min or so how it shakes out.. thanks for the eyeballs
i have this message in my console that I can't recall seeing before.. is this meaningful?
well are you using native arrays?
persistent ones need manual disposal.
yea NativeArray. int[] is managed
i am doing some texture swapping in the app but I'm pretty sure I'm just doing managed arrays and assigning it to the .materials property... are there NativeArray uses there that I need to be aware of?
I'm definitely not using it in my code intentionally
oh, yeah, after looking at the API, I'm not using any of this
perhaps do as is says and enable to get stack traces for them
k well it'll have to wait until after this build.. shakes fist at dialog box
are you creating new textures sorry or just moving around already loaded ones?
should be fine. Ill be off soon but as the others pointed out. You really want to get a memory capture of the webgl player which will require you to enable auto connect profiler.
InvisibleMaterial and NormalMaterial and NormalGunMaterial are all linked in the inspector and static (not static but unchanging)
yeah I'll have to learn how to do that.. I wasn't aware it was possible
In any case, thanks for the help and leads
Yea unity say webgl cannot accept incoming connections hence it needs auto connect enabled to work
here's how i know I'm cooked - 6 purple links when i googled
Could also be webGPU related since that's still not officially released
this is a webgl build - although I'm tempted to try out that 6.1 thing.. they're different, right?
(webgl and webgpu)
webgpu enabled most GPU supported stuff like instanced animating and other compute shader methods that unity uses
vfx graph too
I guess the animating stuff is already done in the shader, but I think compute shader operations are quicker or something?
that's one* of the features they were promoting with it lol
OK... got a crash so @echo coral our solution wasn't successful [enough]. ๐
I'm gonna try the chrome memory profiler again and see if it goes bananas at the point where the allocs happen
Ah, ok yeah. WebGL does gpu skinning in the shader, but WebGPU supports compute shader which actually is a quicker operation than doing it on a per vertex basis
(fwiw I did have to reload/try to crash it 6 times, which is more than usual but still not acceptable)
I was about to say that not every list should be given a big capacity straight away but whatever fits best to reduce resizing.
crash is in the same place too so.. that's actually good news.. having a line of code that I can optimize is infinitely more useful than "the app crashes and I have no idea where"
these paths never get above 19 - and most of the time they're <5
oh yeah that stuff is a pain in the butt to debug. Any time I get some browser errors I just throw my hands in the air and start disabling everything.
Hmm then don't always make them be the max. If you can infer a good size each execution use that
even in the pathfinding code - the units all have movement budgets of like... 3-4 so .. they don't go farther than that.. the only place they'll get above 19 is when the bad guys are trying to find the closest good guy to move towards
but 20 is fine.. 20 allocs should be nbd
Hmm well have a think what else could be improved on, any new arrays or other objects
Wasn't the last time texture related? Are you preloading all these assets at the start? May need to bundle them out and load only what's necessary
This is the chrome alloc timeline but.. I don't know how to read it, and don't see anything obviously bad about it (numbers are in bytes, not megs)
There was some heavy texture use but ... there are a lot of textures in the game, so that seems expected
but the stack trace on the OOM failure is in the same spot so I'm .. really thinking there's a bug in the pathfinding code
but I just can't... figure out how to debug it because it works perfectly (and sane-ly) on my machine and in the memory profiler locally
the line that it crashes on is just a run of the mill Add() call - and there aren't even that many in a single frame (5? 10?)
Could just be many many things building up and that's just what gets it each time.
You ideally need to get a mem snapshot of the webgl build
yeah i'll dig into that thread and add the memory profile emscripten parameter.. and see if i can figure it out
All heap allocations are there uncollected after all
i mean honestly I might just need to rework the API of my hexpoint class to do 0 allocations and cache all that shit elsewhere
i'm just dreading that work though because .. obviously in a hex based game there's a lot of calls into path finding and hex distances!
In this stack trace - is there a way to get more granularity (ie, which line) the issue happened?
i'm pretty sure I have the right add() call narrowed down but i'm not 100% sure
It may help but I could also be wrong and unity is able to do GC more frequently between managed code use. Hard to know but we do know it is going to be less frequent.
OK. I added some more verbose add logging and tracked which frame the adds were happening, and it's definitely the source of the issue. ๐ฆ
it's not out of control for a desktop build, but 1000 adds in a frame (even though the sizes of the lists are small, I think) is probably putting a lot of pressure on the heap
I'm gonna add some code to check capacity and count before every add and see how much my presizing helped.
Ok guys, I got a really weird one for you. Are there any circumstances where calling RemoveAtSwapBack(int index) on a TransformAccessArray could freeze Unity? Not crash it, because of course it could, but hard freeze. Somehow, in some rare code path in my project, calling this function on index zero of a valid access array (with multiple elements in it) causes both the Unity Editor or the build to hard freeze
Attaching the debugger just says Unity is waiting for this line of code to finish executing: _ownerTransformAccess.RemoveAtSwapBack(index);
Im honestly stumped, as this is a core piece of our infrastructure that has been working fine for several years now.
hmm, could this be related to https://issuetracker.unity3d.com/issues/the-editor-freezes-when-schedulereadonly-of-ijobparallelfortransform-with-dependency-is-used ? Im using 6000.0.32f1
How to reproduce: 1. Open the โrepro-ro-deadlockโ project 2. Open the โSampleSceneโ 3. Enter Play Mode Expected result: The Editor i...
100% this issue. Damn. That was a wild time
Hopefully by re using some lists or by making use of the unity native collections you can improve this.
Unity collections package has a native fixed list and native list type that you can dispose when you wish which may be helpful. You can also look into stackalloc + Span<> to ensure a small fixed size array is stack allocated.
Hello, I am trying to create a load/download level system. Let me explain. I want to have a scene with just a plane and then I would like to load a level that my friend created (for example) into my game. Creating a new door in the main scene with the plane that takes me to the new level. Similar to how creative works in fortnite? I am not so sure as I have not played it that much. But that is mainly the idea, be able to load different levels and create portals in the main scene to go those levels. I have no idea how to start with it and I would like to get some guidance, I do not want the main answer. Just some guidance. Thanks in advance! ๐
it highly depends on how you want "levels" to be created, in game or via the unity editor?
Have you looked online for how to make like a level builder/editor? This just sounds to me like needing to save the data for what a level has, then finding a way to share it that you deem fit. The steam workshop should even be fine for sharing the levels if you're gonna upload to steam anyways
In game mainly. Create a level creator/editor tool and then download it and send it to someone
It sounds like you're aware at least of what to do, are you stuck on a certain part?
Not really, I think I need a lot of work to do and investigate before saying if I really need more help. This should work for now. Thank you!
The code for saving a custom level should be pretty simple, I think most of the work here would be making the actual level editor in unity
UI and setting up whatever prefabs
Okay I will try to dig into level editors and probably a lot of questions will come up and might come back again haha. Appreciate the help! ๐
Still debugging this issue but I've found something interesting.. I added some logging to check if the list.capacity == list.count when trying to add items.. and check it out.. a bona fide bug!
So that's super encouraging because.. bugs I can fix.
Now the question is.. why can't I repro this in dev/editor builds? What could possibly be different between these environments?
The part of code in question is the backtracking path finding. Basically I stamp each hex with a "parent" from the origin (and increment the path cost) until I find the target - then I backtrack until I get to the origin. Why can't I get this to fail in dev?
path = new(30);
PathNode backtrackCurrent = _closed[to]; // Shouldn't fail.
while (backtrackCurrent.Parent != None)
{
path.Add(backtrackCurrent.Location);
backtrackCurrent = _closed[backtrackCurrent.Parent];
}
for reference:
private class PathNode : FastPriorityQueueNode
{
public HexPoint Parent;
public float F;
public int H;
public int G;
public HexPoint Location;
}
Basically each node contains a parent and a location (and some A* details: F, G, and H)
And the first node is created with parent = none:
PathNode node = new()
{
Parent = None,
F = F,
G = G,
H = H,
Location = from,
};
_open.Enqueue(node, F);
How do I remove an entry from a StringTableCollection for every locale in script? In other words, how do I delete the entire row?
Parameterless struct constructors aren't allowed (in the unity ecosystem), and property initializers also aren't allowed. I have a struct that might be (accidentally) created somewhere without initializing it properly.
How can I find it?
This is what I want. Am I gonna cause issues by changing the langversion to 10?
something I just realized... 1.3M allocations, that's about twice the amount of datapoints in the parquet file
not sure how to set profile markers but running the deep profile, it seemed to get caught up on this function:
public async UniTask<NativeArray<Vector3>> GetCoordinatesAsNativeArray(DataFrame df)
{
DateTime startTime = DateTime.Now;
float frameBudget = 0.01f; // max amount of time to do work per frame
Debug.Log("Converting coordinates from DataFrame into NativeArray");
NativeArray<Vector3> array = new NativeArray<Vector3>((int)df.Rows.Count, Allocator.TempJob);
// these index values are specific to the trctestimonies.parquet dataset
// TODO: make these values less arbitrary somehow
int xColumnIndex = 10;
int zColumnIndex = 11;
for (int i = 0; i < df.Rows.Count; i++)
{
// System.Convert.ToSingle firmly tells unity that this var is in fact a float so it doesn't panic
float x = System.Convert.ToSingle(df[i, xColumnIndex]);
float z = System.Convert.ToSingle(df[i, zColumnIndex]);
// "0f" is a placeholder for the y axis coordinate, which is calculated later
array[i] = new Vector3(x, 0f, z);
TimeSpan timeElapsed = DateTime.Now - startTime;
if (timeElapsed.TotalSeconds > frameBudget)
{
// reset the start time and wait a frame
startTime = DateTime.Now;
await UniTask.Yield();
}
}
Debug.Log($"Returning NativeArray of XYZ coordinates (y is still 0)");
return array;
}```
What are you converting to floats? I suspect that .ToSingle is allocating here.
floats from the dataframe being passed into the function, which is the same size as the dataset. Gonna change this to do those conversions within the Vector3 creation
Well, damn, that didn't seem to fix it
I guess I'll look out for similar things tho
What type does df[x,y] return?
What exactly happens in the indexer of df?
wym? like why df is being called by index?
Is DataFrame your own class? You are using an indexer [,] with it so I suppose you have the indexer defined somewhere
I'm just suspecting that some boxing is happening there
Ah, no
the actual values in the dataframe are pulled directly from the .parquet file via parquet.net's ReadParquetAsDataFrameAsync() function
the actual values in that parquet file are predetermined
but all the file processing for that parquet file needs to happen at runtime, since it needs to eventually be able to work with other parquet files
@slate spoke fwiw System.Convert.ToSingle(object) is the same (in .net fw4.8) as (float)object and imho a bit harder to read. https://referencesource.microsoft.com/#mscorlib/system/convert.cs,1503
(I didn't read back all the way to the OP, sorry - was just glancing over that code)
I think I remember trying that when initially writing it, lemme try again
I was just curious so I chased it down through the reference source.. and ultimately it ends up here:
(with a few more steps to ensure that it's castable to IConvertible)
that's after rewriting that bit of code to C# array[i] = new Vector3((float)df[i, xColumnIndex], 0f, (float)df[i, zColumnIndex]);
ToSingle has overloads if the type is statically known, that one takes int as the parameter not object
Clarify for me, is the bug it never stopping the backtrack and thus running out of memory?
I've gone so deep... help me :p
There's some bug in my (?) code, but it only happens on production builds. I've .. gotten maybe closer to root cause but I'm still not there yet.
I just don't know why/what would be different about production builds versus local builds.. All my test cases I'm crafting just don't.. fail like I expect them to locally
like.. check this out, this doesn't make sense to me (sec)
the fact this is all "managed" code makes it very weird because you usually only get this weirdness with native code and undefined behaviour
this error ("ERR: 2") happens in an .. impossible way? lemme get the code, sec
these problems usually fall into one of three categories in my experience:
- execution order issues (scripts run in a different order on your target hardware
- framerate/resolution issues (things behae differently because the game runs faster or slower or at a different resolution or aspect ration
- specific intricacies of different platforms (e.g. System.IO cannot read files in WebGL)
plz describe what the difference is specifically
So.. no differences in execution order. No issues with framerate (the error happens all in one tick). There might be intricacies of platform, but I'm not quite sure what/how - something nondeterministic about float priority in my priorityqueue class, perhaps
So .. in the code I linked, there's some checks (ERR:1, ERR:2, ERR:3, ERR:4) that look for an invalid node being added to the backtrack list (where node.location == node.parent.location). This is happening on the origin (0,0) in cartesian coordinates.
I added this check to ALL cases where I Enqueue() ... but in the error message above, that is the FIRST instance of an invalid insert.. and it's getting an item from another queue!
public static HexPoint None => new(-999999, -999999); ๐คจ
In short, the code SHOULD fail when inserting into the other queue (but doesn't)
Basically, there's two queues - _open (locations that could be the path) and _closed (locations that have already been checked). Every location added to either of these queues has a parent (where the location came from - tracing back to the "from" location).
A node CANNOT be inserted into either of these queues with a location=parent.location.
You aren't gaining anything by using out List<HexPoint> path but setting it to a new list in the function...
And yet........ somehow it is
I know - I am tempted to change that but for now, that's not the issue.. There's some situation where the while loop at lines 456 is failing because somehow nodes are getting inserted into open or closed with location=parent.location... and I can't figure out how.
https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp/wiki/Using-the-FastPriorityQueue
There is a "Warning!" section on this library, but I've combed through my code and I'm using it properly as far as I can tell
(But the error could be there!)
I'm attempting to fix my performance issues by replacing my DataFrame stuff with a class type IList, the documentation for parquet.net mentions being able to do parallelism but I assume their example code wouldn't work without converting it to use the Job system. How would this need to be changed, if I need to?
var reader = await reader.CreateAsync(path);
var count = reader.RowGroupCount;
await Parallel.ForAsync(0, count,
async (i, cancellationToken) => {
// create an instance of a row group reader for each group
using (var gr = await ParquetReader.CreateAsync(path)) {
using (var rgr = gr.OpenRowGroupReader(i)) {
// process the row group ...
}
}
}
);```
I'm not sure if it's possible to make an IJobParallelFor that lets you use a FileStream
to clarify, FileStream is relevant because that's one of the override inputs for CreateAsync
Help me understand, is this the check on line 349?
which is necessary for android
Nope - that one is "ERR:1" (e() prefixes the logging with "ERR") - the check that's showing up in the console is on line 377
aha now that makes more sense to me. So would this be created by somehow adding a neighbour PathNode but somehow its parent was set to itself?
In short - the check on 377 is looking at the freshly dequeue()d item for badness.. But ALL the places I enqueue are doing the same check (and none are being hit)
Like, in other words - I'm never enqueuing bad data but somehow I'm dequeuing bad data
I thought that - and so double checked the origin math, thinking there was an error in GetAdjacentHexes() (line 530)
I just spit out the hexes adjacent to the origin in the editor and browser, and they're both working as expected
(left editor, right browser)
Another possible guess where there's a difference in platform is the code around line 76 - it's code that I only vaguely understand to convert X/Y to Q/R/S
but my tests on/around the origin seem fine for that
The only thing that stands out is your use of AggressiveInlining. Perhaps on prod il2cpp this will actually inline the function call and perhaps there is a bug relating to the inline?
I dont think you are going to gain much from using it on GetAdjacentHexes()
I don't think it does anything, actually
but I left it in there as a freeroll ("couldn't hurt")
in managed world i have no idea if it has an effect (don't think it was confirmed that .net actually uses it) but in cpp it certainly does
i'm gonna add some checks to Dequeue() since this libraries code seems weird to me
I mentioned it as we know its not happening in dev builds
yeah.. honestly I'm sure there's some low level bug here and I'm kinda at the end of my patience for this one
like the error i showed above is .. not possible
I'm not changing my nodes (once created), and I'm checking them for validity when enqueuing, and when dequeueing.. and somehow I put good nodes in, and bad nodes come out. ๐คทโโ๏ธ
I was literally tempted to change struct to have a _isInitialized bool and add a check in the x and y property getters against the flag
but that woulda definitely been some major overhead
(and probably not tell me much anyway)
is there a page for HPPriorityQueue ?
HPPriorityQueue just inherits from this queue lib
sorry that's wrong - HPPriorityQueue is a FastPriorityQueue<PathNode> and PathNode inherits from FastPriorityQueueNode
private class PathNode : FastPriorityQueueNode
{
public HexPoint Parent;
public float F;
public int H;
public int G;
public HexPoint Location;
public override string ToString()
{
return $"{Location}, FGH:({F},{G},{H}), Parent:{Parent}";
}
}
Nothing fancy here though
(perhaps aside from no constructor - so the Parent and Location are uninitalized/undefined if pathnode new() doesn't define them.. but I am everywhere in my code, and I am not gonna comb through the authors code in his library)
well remember you are using -999 or whatever as your "none" state vs ofc the default is 0,0 for your positions
yeah, but that's fine - ideally I'd like to even have x and y initialize to -999999 so I could see if they were being .. uninitialized .. but that's not allowed in clang 9
(ie - parameterless struct constructor and/or property initializer)
why arent you using the int min but loads of 9's
because if I have a bug and accidentally try to check adjacent hexes of HexPoint.None I won't get int underflow
you mean c# 9 not clang ๐
cslang9 ๐ whatever you know what I mean ๐
clang is a cpp compiler so i got very confused
perhaps your none state should only be if x or y is less than 0
but well not the main issue here i guess
no, cuz those are valid locations in my map
0,0 is a valid location too, which is why I don't use that as "none" or "invalid"
(in retrospect we coulda just moved our hex to origin = 100,100 or something but .. that ship has sailed)
aha i see. im kinda out of ideas atm but if you can inspect more if that queue does anything funky that may help
Perhaps also make sure any PathNode made is given a default value matching your none state as on 362 for example it isnt
Yeah, could do that too. I'm more or less giving up because I've spent maybe ~20 hours on this single stupid issue and .. I can just deploy a dev build and it works fine.
I'm maybe going to make a minimal reproducible project and see if I can isolate exactly what is going on. I just keep coming back to "it's so damn confusing that it only happens in production builds".
Once had some cpp code only crash in prod but then I found I was writing way out of bounds on an array but dev builds happened to have allocation that avoided a segfault. Sometimes it's stuff like this
I've found the error, actually ( ๐ ).. It is my code but it's also the author of the library not throwing an exception like I thought it would when trying to dequeue an empty queue
but weirdly, it only throws locally - not on production builds.. so i'm exploring that
line 367 here doesn't throw (when it should)
go figure
Don't think I have the energy to step through his code.. but his .count property works so .. I can just check if that == 0 instead of just trying to dequeue and catching the exception.. and ... hooray, I have my life back.
Yay success
This setting for exceptions - I still should be seeing/getting exceptions in my builds, right? Like - my code looks like it should still see exceptions?
The code for dequeue looks like this:
Like - that should still throw an exception to my code, even with Explicitly Thrown Exceptions Only, right?
If built without the DEBUG symbol (which should be the case on standalone releases), code between lines 352-363 will not be compiled ie. it won't exist at all, so the exception won't be thrown
DEBUG covers dev builds and editor
I wonder what it classes as non explicit thrown exceptions, like an array out of bounds isn't?
the DEBUG symbol is defined for my production builds (not sure how or where, but it is - this code appears to run)
yeah, verified - stepping through the code hits these lines (in the production build settings)
out of curiosity, do y'all think using DataFrame or SQL would be better suited for large dataset stuff in Unity?
Sqlite is a popular choice
how large?
generally SQL and data frame supporting databases are not fast
75MB as a .parquet file, 675k rows
what operations do you want to perform?
is it just one table?
if you just want to read it, there is no reason to use a database, there is stuff like this library around: https://github.com/aloneguid/parquet-dotnet
any processing without the overhead of a database is likely faster
Initially, yes. Basically, each row has a set of coordinates that's being used to place an object in a massive procedurally generated environment, each of those objects will be sorted by the terrain chunk those coordinates would fall within and then rendered via compute shader
or, so zero benefit from having it in a database, also 75MB is not a lot
but, each of those objects also need to be selectable so you can view the rest of the data associated with it
trust me, I'm too familiar with this
I hate it
viscerally lmao
the only useful output you can get out of it is DataFrame
and I think that's one of the biggest hurdles with my performance issues
also documentation leaves a lot to be desired
not to mention the hurdles to jump through to get it working on android properly
well, if thats not your cup of tea, then maybe you just have to make a detour through a RDBMS
those aren't exactly easy to get to work properly either
fair, but I assume also infinitely more well documented
you'll have to find out if that kind of documentation is actually helpful to your problem
Would something like this not work well?
https://assetstore.unity.com/packages/tools/utilities/sql-for-unity-database-115308#reviews
if you ask steve its the best thing in the world
lol
i would think its not supposed to be a reader for a parquet file though, maybe there is an import option... i wouldn't know
true but the parquet file could be converted to SQL before runtime
kinda defeats the point, but sure.
The input database type just needs to be a standard unprocessed file of some kind
that way it's easily adaptable to other similar datasets
How do I dynamically control the height of a small part of terrain and flatten it from code/logic?
Example: Wherever any item is placed on a terrain, that item's space required portion of terrain gets automatically flat
https://docs.unity3d.com/ScriptReference/TerrainData.html is that what you might need to use? Updating the height map?
Does anyone know if there's a way to hide the track binding on a custom marker track (in timeline). It seems to default to a gameobject. If I inherit from just TrackAsset, it doesnt give me the option to add my custom marker
I have issues in my game where my main event bus isn't initialised when other scripts want to access it - what is the best/ safest way that proper game devs make sure the correct order of things being initialised?
Should I set just the eventbus in the Project Settings > Script Execution Order - or is that v bad to do?
Is it better to set a yield return null check for all other systems that rely on the eventbus being initialised? that also feels suboptimal and not scalable
Thanks in advance for any help
Thereโs also DefaultExecutionOrder attribute, I use it for fundamental stuff like DI container initialization. Then I just inject dependency, which could be plain C# class so you donโt need to deal with Unityโs initialization methods.
Ah ok interesting, I'll check out that attribute thanks
- Follow the rule of thumb:
- Awake for self initialization
- Start for things that depend on other things already being initialized
- Consider lazy-initialized properties
Ok thanks - where does 'OnEnable' fit into that priority list?
OnEnable runs right after Awake when first starting up, so it's similar to Awake
im so angry rn. My only code for loading audio files durring runtime has turned out to now be able to read most WAV files and is useless. And any other solution is just not working. So how do i load an audio file as an AudioClip durring runtime?
Unitywebrequestmultimedia
oh ok so the only way to do it is the dumbest, most annoying and hardest oneยจto work with. Yeah, great. I wanna break something.
you can also use resources, addressables. Not sure, whats so hard about a simple unitywebrequest?
Hey there, I've been pulling my hair trying to make an FPS controller for my game with ECS. But I cannot find any resource online to provides a strong start. Even the official Unity Character Controller is literally broken and doesn't work at all...
Do you guys know any sort of resources I could use? I need to also support physics (which is the main issue really)
Hi everyone,
Is anyone else experiencing significant issues with the new UVCS? Iโm struggling to understand how they calculate limits, and the lack of clarity is frustrating. Recently, UVCS notified us that weโve hit our total limit, even on a day when we didnโt upload anything. After opening a ticket, they couldnโt provide a clear explanation and are now pushing us to upgrade.
Hereโs our situation:
- Our game project is around 12 GB in size.
- Weโre a team of two developers.
- Daily data flow is less than 100 MB.
Iโm wondering if thereโs a better way to work with UVCS or if we should consider switching to another source control system. A few specific questions:
- Does the UVCS client update the repository automatically?
- Could it be counting files in the library folder toward the limit?
- Are there any recommended alternatives for a project of our size and scale?
Any insights, tips, or recommendations would be greatly appreciated!
Thanks in advance.
it counts all previous versions of all controlled files towards the limit
Hey, is it possible to export a ui toolkit hierarchy (children of an particular VisualElement) to single image? Working on an image compositor and I am having trouble with finding a way to combine all the layers and export them. USing a camera and taking a screenshot doesn't retain the aspect ratio of the page and the resoliution is a bit low. The resulting image will be printed.
got it
Is it possible to pre-load a scene, then open it later? I'm aware of AsyncOperation.allowSceneActivation, but since it blocks the loading of other scenes it isn't a good option. Setting the root GameObjects of the scene to inactive as soon as LoadSceneAsync finishes also doesn't work because this invokes Awake, OnEnable, and OnDisable on each component. Is there a workaround to this or am I out of luck?
Maybe set the root object to deactivated in the editor? So that it is inactive on scene load.
That might work, but it's not very intuitive. It also creates a lot of edge cases.
Isn't this what subscenes are for? Like in the mega city demo from years back
Unity's kind of shit for this afaik
Might be worth considering having your own comparable awake and start messages that whatever manager your using calls after the scene is ready rather than using the build in awake and start
If the scenes are additive it does not block loading of other scenes. Our levels are actually composed of multiple scenes for loading time optimisation and we set them to active one after the other.
Also root objects in the additive scenes are inactive by default and we enable them in batches on scene activation
the fact it's async and i need it sync but due to how async works in Unity with Corutines i just can't get it to work how i want it to.
to me its not simple at all, i never understood and will never understand async propably.
oh great im not the only person who has this issue- oh they're calling them stupid, ok...
https://discussions.unity.com/t/synchronous-unitywebrequest/764763/2
I was trying to use this, but even tho the build does recognise NAudio namespace, it does not recognise the Mp3FileReader, WaveFormatConversionStream and WaveStream classes
https://www.youtube.com/watch?v=fIW-_zxaCPM
Twitter: https://twitter.com/_acetix
Here is a simple tutorial of how you can load any music files into your project.
-------------- Downloads --------------
NAudio.dll: https://www.dllme.com/dll/files/naudio_dll.html
NaudioPlayer script: https://www.dropbox.com/s/wks0ujanr0pm6nj/NAudioPlayer.cs?dl=0
The Filebrowser I used to get my path: ht...
Btw, yes, i really want it synchronous. The request is part of a loading sequence, that shouldn't finnish until all data is loaded. Async is useless in that moment
This is the script i have now. So far i tested it once and it caused a Unity crash.
public class WavLoader : MonoBehaviour
{
public static AudioClip LoadWav(string filePath)
{
GameObject loaderObject = new GameObject("WavLoader");
WavLoader loader = loaderObject.AddComponent<WavLoader>();
AudioClip clip = null;
bool finished = false;
Coroutine corutine = loader.StartCoroutine(loader.LoadMp3(filePath, (a) =>
{
clip = a;
finished = true;
}));
while (!finished)
{
loaderObject.GetComponent<MonoBehaviour>().StartCoroutine(WaitForOneFrame());
}
Destroy(loaderObject);
return clip;
}
private IEnumerator LoadMp3(string filePath, System.Action<AudioClip> onLoaded)
{
if (!File.Exists(filePath))
{
Debug.LogError($"MP3 file not found: {filePath}");
onLoaded?.Invoke(null);
yield break;
}
string url = "file:///" + filePath;
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG))
{
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Error loading audio: {www.error}");
onLoaded?.Invoke(null);
}
else
{
AudioClip clip = DownloadHandlerAudioClip.GetContent(www);
clip.name = Path.GetFileNameWithoutExtension(filePath);
onLoaded?.Invoke(clip);
}
}
}
private static IEnumerator WaitForOneFrame()
{
yield return null;
}
}
that's because you create an infinite loop that does nothing but start pointless coroutines over and over
while (!finished)
{
loaderObject.GetComponent<MonoBehaviour>().StartCoroutine(WaitForOneFrame());
}
this seems cooked maybe?
You might just need to look into tutorials or unity learn stuff about async. Your problem is, that you only know a loading process based on blocking the mainthread here, which you cant wrap your head around the async webrequest. But in the end, you can either make your whole loading async and await all async loads or you just block your mainthread with a list that you are waiting for to empty. When loading the files, add them to a list and wait remove themselves when done, check for your lists count == 0 and continue. Just because you cant adapt to the correct situation does not mean, you have to force the wrong one. Dig into async code, learn what it is doing and how you can collect information from it while loading and use that to utilize in your loading progress system.
In that way you also would learn the correct way of loading things async, because blocking the mainthread means blocking your game. Imagine you want to load while have an animation running, even that could be blocked if its run by code. Or imagine you want your user to check a list of things and lazyload. You would kill the experience when loading new stuff in while its doing so.
As others have said before me, your while loop never stops so it freezes the main thread forever (including the editor). You need to yield till the next frame or for some time instead in this loop.
You are doing something very weird in that loop too you must be confused how coroutines work...
hi, i learned one of pitfalls of using c# is Decompilation, i am making a multiplayer game so security is paramount. I looked into using c# native to compile my project to x86 directly. is there any other tools or compilers or coding practices I can use to minimize the security risks. I know about the whole don't trust the client one the server approach, but I still want basic code obfuscation. I thought about also writing large sections of my code in c/ cpp and use a c# wrapper
You can decompile C/C++ as easily. If people want to do that, they will.
you can never fully mitigate this but there are tools that can "obfuscate" your c# to make decomplication harder to read
As long as you dont do what gta online does and trust whatever the client says then you will be good
well you can ditch the cpp symbols and break it down just to just memory but from what ive seen c# keeps almost the exact same script
c# retains type naming and lots of information about the type structure for reflection (and due to its managed nature) so its just how it is
you don't do network security by obscurity
even if you use il2cpp there are tools specifically made to decomp il2cpp cpp to semi readable code
If it's a mono backend, then it's compiled to an intermediate language, which is more readable than assembly and easier to restore "original" code from. I think if you build Il2cpp it should be as as safe as a C++ game.
i know that, however i also dont want people just copying my scripts
if they want to they will, you can't stop it
ultimately you have to give the user your code for them to run it haha
Lol, who would want to copy decompiled code? Are you developing rocket software for nasa or something?
then dont share the game, simple
Build an il2cpp build and the decompiled code would mostly be useless to anyone but assembly experts. And even then it would take them several months to years to do anything useful with it.
the only case where you'd actually be able to hide code is if you have some client server architecture. like online games where the client isnt the one who needs to run logic
and even that case is very rarely ever needed
thats what im doing, im compiling the project into a linux headless server and then i have the gui client
Not something to worry about until your game has lots of players.
then you'd easily keep the server code private by not sharing that. You should specify what you're actually trying to hide because this just seems like the common pitfall of "I need to be secure!" so far
Trust me, if you have the problem that so many people are playing your game that there's more cheaters than you can manually ban, you have probably the best problem any multiplayer dev faces
I released a MP-only game that topped Steam New Releases/had 90k owners + had prized tournaments. 90% was client side. Had 2 cheaters the whole life cycle of the game, both of whom were banned fast.
Maybe only 2 that you've caught. It's not bad to just start off by implementing a better approach, especially if it doesn't take much longer to do.
Which is why im specifically trying to see what part they're trying to hide, so we can see if its worthy of even dealing with rather than repeating the same statement 50x
If your multiplayer game has client authority then you are cooked
That's a very naive statement
I've successfully reverse engineered obfuscated code several times. So not always perfect either.
not sure where you got the idea that they stated it was perfect. in the same message you're replying to, they specifically say "harder to read" AND "never fully mitigate"
well new question, i currently have one unity project for the cilent and server, is there any macros build into unity to tell it to only include specific code is server builds?
It's not
As a baseline maybe just scripting defines? With Unity's new Build Profiles you can setup a Build Profile for the server that has #SERVER_ONLY defines
.NET native AOT is a good choice here. You can trim out a lot in the process and you'd basically have to use Ghidra to decompile, which even then doesn't have the original symbols and metadata. Recompiling would be nuts with that as well.
Yeah I know what they said.
thats what i was looking into however i couldnt find any resources on using it with unity
What environments are you building for? It should be very easy to accomplish for desktop environments.
linux server, linux and windows client
Just native compile a library and libraryimport it and use it with interop. Boom, a native library used in your code.
Perfect.
That's basically il2cpp
Yeah just make a classlib and native compile it and then use it in your unity code.
Then hate yourself for how difficult it will be to integrate
What are you talking about interop is easy if you control the lib you're integrating with
That's Unity-specific, which is a fair option. Just stating a .NET option so the code could be used by other systems outside of Unity if wanted.
You still need to then use managed code with unity APIs so I doubt it will be very impactful
That only works to "protect" the class library code though, not the code in Unity project. Unless you write your entire project in those class libraries.
Hahaha this convo
But we're talking about trying to protect the core code as if it were native.
Yeah treat the native code like it's a plugin. I'd only do very sensitive stuff in the native code lol.
Would also recommend Anti-Cheat Toolkit if you want some more 'low-hanging fruit' ways to deter the majority of script kiddies
Is that toolkit free?
Nope, unfortunately. But having used it, it's well written
Well, you better hope you don't change whatever those code often then, because every time you change them you have to recompile and reimport into the Unity project, it makes the entire process so painful to work with.
Nice. Just set up some MAC address ban logic and you'll anger the script kiddies lol
Yeah
Personally I consider going down this path as just a futile attempt at fake security. It weeds out the bottom barrels, all it takes is one person who cares about your game enough to cheat and it's back to square zero again.
So in conclusion.. No. client side obscurity doesn't work thanks for coming to my ted talk
also another thing, if im running multiple instances of the server is there anyway to used shard memory server side as a optimization, i know how to do it in cpp but idk how it would work in a unity project if at all
Basically
I just don't want to load the map 50x in mem
Here's the thing. If the bytes of a program are on your file system, they're fair game to play with.
True, but if you mess with blocks of mem durring exec then that's iffy
This might be difficult with unity. Luckily, you don't have to use the same engine both for the back-end and frontend.
So having other parts have checks and balances, hashes, checksums, etc. can help
Yeah you gotta be a wizard to pull some of that stuff off.
You could have shared asset bundles for assets but in memory sharing won't happen
You can even have code in those assets I believe. ScriptableObjects in asset bundles and addressables (I think, I may be wrong)
SOs aren't code.
yeah just trying to free up some mem by not loading the same models over and over again
all that will be handled by unity in native code so you would have to modify the engine so you would need engine source (i presume)
Lol you're right.
Is this your own server or is Unity somehow involved? If it's your own backend I'd recommend distributed caches, memory mapped files, etc.
i know its a bad way of doing it, but i have the unity game project that im compiling for the client and the server the server is headless and just handles connections and physics using unity, idk how i would use my own solution without making my own networking solution and making a physics engine that would match client side physics predictions
Are you using Mirror or something?
i thought this method would be best to keep coherency between the client and server
im just using fishnet then compiling the unity project to the linux server build
then i can run the unity server headless from terminal
Tbh this is another super premature concern. You may get to your final game, and find out that memory isn't the bottleneck for instances-per-server at all, and it's CPU limited.
Having the backend code within the Unity code base is definitely not something I'd recommend, unless the code is strictly networking code for multi-player, in which case Mirror has a good implementation of such an architecture.
This
well idk how else i would write the backend, but i can alsway handle large portions of the logic with a dll or only compile the logic to the server target only. eventually the client will just send input to the server and ill handle everything server side, and ofc the animations and stuff will still be in the client just not sent to the server
What protocol are you using to communicate with the backend?
i belive fishnet uses netcode
If you're just managing state I don't see why you need netcode. You could make your own HTTP backend and have a RESTful implementation of state.
true
http is not well suited for "near realtime" games
well most games use utp
udp
Id try to research what other large multiplayer games made with unity do (e.g. rust, among us)
yeah, funny enough one of the among us devs responded to that question on r/gamedev
KCP basically
Again, depends on what state we're talking about managing.
Has anyone used a standalone structured logging service to the cloud from a client? I'm thinking of adding Seq to a project, but I'd like the logs to flow up to a common logging instance and not quite sure what pitfalls might await me
https://gist.github.com/Togusa09/c2dbeb103ae47ebde01341b22818afee
(Seq works on the same machine just fine with a localhost call - but I'm not sure if this is gonna fall flat using potentially tons of UnityWebRequests)
Obviously the implementation here is gonna need to have as minimal logging as possible so the logging isn't putting a lot of demands on the client (and server, but that's easier to deal with)
Do you have different goals for dev and prod? Usually for prod you only care about error logging and hopefully its infrequent enough to not be such an issue.
For games I work on we mostly use firebase crashlytics for error reporting. I've also used loggly and sentry in the past. Sentry was my favourite as it has many supported clients (inc unity) and you can self host the server side too.
hell i even wrote something to log tf2 sourcemod errors to a sentry instance!
Goal for this project is 90% user behaviour/analytics and 10% crashes/ANRs (the client hasn't told me that crashes are an issue)
They have pretty low retention/monetization and are bringing on a new product manager
well you should care about errors and/or crashes
but when I looked at the app there's like... a lot of hand waving and guessing for why.. so I think that a good goal would be realtime logging of user interaction
they're already using firebase crashlytics but there aren't much in there
frankly the userbase is kinda too small to make any good guesses as to the lack of monetization/retention/engagement
perhaps then you should be using firebase analytics too
then that should already cover your needs?
I just don't know that analytics is easy to ... explore use in an ad hoc way
it might - to be fair they're using FA in a very light way.. like maybe sending 10 different types of messages total. I was thinking structured logging would give a lot better insight into user flow
maybe FA can do that just fine too - provided we go and add a zillion FA logging calls in the client
From my experience you log major parts of the game in a way that lets you track user progress.
e.g. levelStart (with level related params), levelSuccess, levelFail. This usually also includes monetisation related events too to track revenue.
sentry doesn't work with c#..?
sentry has a unity plugin
This is kinda getting of topic anyway but if you already have an analytics service you should use that to log your main game events. Ideally you query the events in a db later to get a wider picture of how the game is being played.
No, definitely not OT - I'm gonna be the one implementing whatever the solution is so .. exploring other options (including just using what they've already implemented) is totally relevant
Sentry looks nice
I might just honestly need to get better versed in FA and see if we can improve the event flow to that and get better insight
aha right. firebase analytics has an 500 custom event limit and also limits how many parameters you can send max on an event.
So its usually better to send events like "gameMove" with params to give detail vs "gameMove_0_foobar"
guess the service you pick is up to you/cost
yeah, that's probably fine.. I was thinking of defining some sort of dictionary of structured logging "types" since Seq does the same sort of thing - collapses the stringy bulk of a message into a small primitive for network transport so it's not spammy.. although it doesn't have a event limit
mostly I'm hoping that whatever reporting/analytics on the back end is... useful for the product manager who might not be familiar with the product
seq doesnt look like the correct solution then. actual analytic tools usually have nice UI to quickly parse useful data (e.g. current active users, countries, common events ect...)
What I liked about seq is if you logged something like
_logger.Info("{Player} started task {Task}", myPlayer, myTask);
You'd see this stream of events in the dashboard, and you could just click on {Player} (which would render however you want .. like, maybe the player name with a guid:)
Sharping#1234-abcd started task NewbieTask0001
If you clicked on the player - you could just filter on that player and so you'd see the event flow of everything that player was doing (or did).. in realtime
I think they need less of that high level stuff and more granular tracking - like "what is the user journey before they churned out" versus "what percentage of users churned out after d3"
they have the latter - and it's grim ๐
But I don't think they have the answer to "what's the last or most annoying/confusing/hard thing a user did before never coming back"
seq has dashboards too but it's not their strength imho
For a game with "levels" we can usually identify this stuff by seeing how many people start/finished levels and ofc as we go up the levels we see a drop off.
So if you can track some common game events in an easily order-able way they should be able to do the same.
yeah this game's a little more "open world" (not really, but more like.. lots of small things they can do) but.. there's still probably a lot of value in tracking the engagement more finely - like "started merge board" "closed merge board" "completed task" "collected resources from world map" etc
well you can log whatever you want i guess but think about what major things need to be there. regardless of platform you use its important.
logging random strings doesnt cut it.
I think basically what I'm looking to provide is "here's a readable script of what a given user did" in a session.. FA might be that, but I don't think I've really used it that way in the past.. FA seems better for aggregate queries
yeah, definitely
have a think then what major information can be used to know the "players progress" (e.g. level, play time, resource count, xp...) but hopefully this has helped you a bit. You can always have some generic "board_event" with some params and other events like "levelUp" or "resourceCollect".
k one crashout and a fieldtrip later:
public class WavLoader
{
public static AudioClip LoadWav(string filePath)
{
if (!File.Exists(filePath))
{
Debug.LogError($"MP3 file not found: {filePath}");
return null;
}
string url = "file://" + filePath;
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG))
{
DownloadHandlerAudioClip handler = new DownloadHandlerAudioClip(url, AudioType.MPEG);
handler.streamAudio = false; // Ensure full loading instead of streaming
www.downloadHandler = handler;
www.SendWebRequest();
while (!www.isDone) { }
if (www.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Error loading audio: {www.error}");
return null;
}
AudioClip clip = DownloadHandlerAudioClip.GetContent(www);
clip.name = Path.GetFileNameWithoutExtension(filePath);
// Ensure the audio data is fully loaded
if (!clip.LoadAudioData())
{
Debug.LogError("Failed to load audio data!");
return null;
}
return clip;
}
}
}
i got the solution.
now i just have to rename the functions and make it support multiple files
while (!www.isDone) { }
this is going to cause the entire game and editor to freeze. this should be a coroutine
Yeah, it will freeze up until the request is finnished. When im loading the audio file, it's always in moments like loading an entire level, so the app is expected to freeze up.
that would be a complete freeze though, wouldn't it make more sense to do that over several frames so you aren't completely freezing and can instead show a load/progress bar or whatever?
Yea don't do this...
oh, i just realised what im expected to do
The Start() is part of some while that Unity initiates, but no Start is async, they go one by one, so putting this in a Start freezes up the app... and the whole content of Start is supposted to go to a Coroutine that Start starts, right?
If you don't want to use coroutines use async instead via Awaitable or unitask
Doing a while forever will always block a thread BUT if we await or yield within it we break execution till some point later (which then means we don't block the thread for ever)
Await for the win
I use async with UniTask a lot
oh yeah Async is MUCH better.
Has some extra things you need to handle in unity specifically but do change what you are doing now
you can just define start as a coroutine
private IEnumerator Start()
{
// magic!
}
@glad cypress
oh cool
you can also have a coroutine function anywhere and start it with any mono (but it them depends on that mono to be executed)
async does not have this limitation but you need to make it stop when playmode ends (unitys Awaitable probably does this better)
ok cool but why do all the tasks get stuck on the Load___ functions???
protected async Task FileLoadCoroutine()
{
var iconTask = Task.Run(() =>
{
Debug.Log($"Level: {Name} icon start");
var icon = LoadIcon();
_icon = Sprite.Create(icon, new Rect(0, 0, icon.width, icon.height), new Vector2(0.5f, 0.5f));
Debug.Log($"Level: {Name} icon finnish");
});
var backgroundTask = Task.Run(() =>
{
Debug.Log($"Level: {Name} bg start");
var background = LoadBackground();
_background = Sprite.Create(background, new Rect(0, 0, background.width, background.height), new Vector2(0.5f, 0.5f));
Debug.Log($"Level: {Name} bg finnish");
});
var musicTask = Task.Run(() =>
{
Debug.Log($"Level: {Name} music start");
var music = LoadSong();
_music = music;
Debug.Log($"Level: {Name} music finnish");
});
await Task.WhenAll(iconTask, backgroundTask, musicTask);
filesLoaded = true;
Debug.Log($"Level: {Name} - ic:{Icon != null}, bg:{Background != null}, au:{Music != null}");
fileLoadFinnished?.Invoke();
}
It just logs the start of all the functions but not than none continue.
Task.Run() executes the code on another thread. Unity api functions will throw an exception when used on another thread
async is not just for "doing work on other thread"
public async UniTask DoThingAsync()
{
Debug.Log("Hello");
await UniTask.Yield();
Debug.Log("Hello next frame");
}
ive said this on this server soo many times I really cba
than i do not know how to fix my issue. Elaborate.
all youve told me so far is that im doing something wrong.
theyre not trowing exceptions tho... or like... you mean that it will throw exception and not log it?
this does not help.
yea the exception is just not logged in the unity editor. if you attach a debugger and enable "break on exceptions" then you will discover them.
UniTask has .Forget() to correctly send exceptions for non awaited tasks to the unity console
my example shows via unitask that we can "await the next frame" and because its still on the main thread, we can use the unity api safely still.
Just like a coroutine!
@glad cypress ^ some reading for you above
oh yes i do love me some reading my project is due in a week it's 23:33 guess im not graduating, F me.
stick to coroutines if you understand them
Check the example here for how you can yield and wait for a unity web request in a coroutine func https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Networking.UnityWebRequest.Get.html
or if you really want you can do
while(!done)
{
yield return null; //WAIT FOR NEXT FRAME BEFORE CHECKING WHILE CONDITION
}```
i dont understand any of this. but i guess ill try unitask...
Nah i don't recommend it. If you don't understand coroutines, async will be harder and give you more problems.
what am i supposted to do than???
Exactly as they were telling you above? Stick to coroutines
If you have a problem with trying to use a coroutine then specify what that problem is
Though it's really not suited for the advanced channel imo
Working on grass painting for my cvustom terrain system. The grass is instanced geometry drawn via DrawMeshInstancedIndirect. Whenever the user paints, I erase/dispose the current computebuffer and then recreates it with the list that contains the newly painted details. This causes a very noticable and distracting flickering.
I'm not entirely sure how to fix this. A quick google search on how to update computebuffers properly, I see stuff like "SubUpdate" buffers, with very little further explanation. Can anyone help explain how I can properly update a computebuffer to account for new data without erasing it and rebuilding it?
public void UpdateDetailBuffer()
{
if (mpb == null)
mpb = new MaterialPropertyBlock();
if (allDetail.Count == 0)
return;
//Release current buffer
detailBuffer?.Release();
//Recreate buffer
detailBuffer = new ComputeBuffer(allDetail.Count, Marshal.SizeOf<DetailObject>());
//Set new data
detailBuffer.SetData(allDetail.ToArray());
mpb?.SetBuffer("_TerrainDetail", detailBuffer);
}
This is my current code for updating the buffers
SetData has an overload that allows you to write from a specific index onwards. You create a big enough buffer initially and keep track of the last index written to. Resize like this only if you need to.
I've tried that, but I don't really understand how to use it. Documentation didn't really help and I can't find any examples of it's usage
K, redid all my code with coroutines - looks like it works. Shaders are making problems now tho...
if there's only the error and no code, its probably a question for #๐ปโunity-talk
I don't know where exacutly to put it but anyway guys is it possible to make binary patch by using package bsdiff and apply it for files like .resS .assets because for know i faced alot of toruble trying to do it i am working on patch system for unity game my q is should i get try using assets bundel instead of patching using binary diff for .assets and .resS or what
addressables (which uses asset bundles) has support for "patching" as you can update content later by using a remote catalog and/or remote bundles.
They can be hosted online or be in the filesystem somewhere
so me trying to patch ,assets file and .resS was pointless right
and was just wasting time
yea dont think you should bother unless you want some diff based version patching like steam does
my upload is so slow like 100k/s that's why i don't wanna upload game to my game luncher all the time when i change somthing for now changing code ican just upload patch by program i made using bdiff package but i faced problem when there is assets so i am gonna try what u suggested and see if that will help me
yea if you have your "local groups" be somewhere like streaming assets you can avoid re uploading the bundles if they didnt change
(normally local addressable groups are embedded in the game but you can make the output/read path be whatever you want basically)
I'm getting terrain height differences between the terrain chunks showing gaps between them
A tool for sharing your source code with the world!
Ive optimized the bottom section of code into the top section of code yet its now slower.
At a glance does anything indicate why the top section would be slower than the bottom?
https://pastebin.com/THxYFd4D
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
The profiler can.
good call, kind of forgot i can use that
ill give it a go, thanks
Unity wont let me run the visual studio profiler with this project
i can just profile this outside of unity i suppose
wdym "visual studio profiler"?
You should use the unity profiler in the editor. You can attach it to a build if you want.
Can the unity profiler profile specific functions?
I tried it and dont think it produces much detail unless im missing something
ill look into it more if it can
Yes. You can add profiler markers to your code if you want to look at specific sections inside a method. By default it would measure timing for each method.
okay ๐
yeah im working on it now
This profiler is so unuseable
Okay so ive got multiple performance markers that run, and they show up under performance markers but when profiling those markers do not show up in the call stack under any frame whatsoever
I think i need to scroll back the profiler preview but there seems to be no way to?
Wdym? It's great.
Im starting to get it now but how can i view further than this period?
You can only view the cached frames. You can change how many frames are cached in the editor preferences
You can't.
Make sure the frames you want to profile are within the cached range.
yeah alright.
What does self ms vs time ms mean in the categories?
Why doesnt each element in a dropdown's total MS add up to the parent MS?
if OldGenerateVertList takes .37ms shouldnt its children fucntionality take 37ms total aswell?
Self is the method time - the neste methods time. The other one is the total.
yeah okay t
thanks @untold moth
thought there would be the thank bot lol
It seems if statements are faster than accessing a small list to deprecate those if statements in favor of a mapping?
Mapping would usually be faster. If it's using hashes.
I'm not entirely sure you're comparing now and what info your conclusions are based off.
One definite difference is the number of times you access elements. O. The new approach there's like 30% increase.
yeah i noticed the difference that made when profiling, but now their both accessing the same amount of times
one just uses if statements
and one iterates and uses a list instead of an if statement
is there a way these if statements are just completely optimized out
these?
yes
if only one can be valid at any given time, then if - else if
not the case here
Im not trying to optimize the if statements though, im trying to find out why their faster
Share the new profiler info where the number of list access is the same in both cases.
Also share the actual code including the method signatures
The definitions yes, the ones that you shared code from
The one's that you are profiling
At this point the definition of the VertexInterp function isnt important, but now the code is alot more similar so almost exclusively im wondering how C# has fully optimized these if statements out
https://pastebin.com/6tSMmCpC
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
This is nitpicking as these functions dont seem to be very impactful even in extreme circumstances so for now its just my curiousity
What's m_NewGenerateVertList? Can you share the whole script please? or at least the methods this code is in?
m_NewGenerateVertList is the using statement in the code sample. Its the performance marker
same with m_OldGenerateVertList
both of these code sections are running one after another for profiling purposes
But ive also found using stopwatch the top section to be slower so theres no issues with running these concurrently in terms of benchmarking
I wouldn't say this is a fair way to compare them, but let's assume that's not the issue.
Are these all lists?
Yes
Ok, so there are already more list access in the top method
Even so, edgeIndexTable is static+readonly so it should just be fully compiled
The difference mainly comes from you calculating indices(with bit shifting) dynamically, while in the bottom solution they are hardcoded.
Not sure what you mean by that. It's still a list access. It doesn't matter where and when the elements were added to it
If you want to reduce list overhead, use arrays
Though, in a prod build there's probably not gonna be too much of a difference if at all
Im not sure if its different because C# is jit compiled but as far as im aware at compilation that static readonly list doesnt exist anymore nor the bitshifting operations; just the values of the list put in place of where their used
I don't think that's a thing with a C# compiler. Definitely not in a debug build(editor)
And the bit shifting is most definitely not gonna be inlined or turned into constants.
So if static readonly values arent compiled then why are if statements?
thats interesting
which part of the bitshifting do u expect to be turned into a constant?
all of it
Wdym by "not compiled"? Everything is compiled. static readonly mostly dictate how these fields can be accessed.
It might be used for optimization as well in a prod build. Not 100% sure about that.
edgeIndexTable[i] will always return the same value given the same i and henceforth that value bitshifted the same way will always be the same
In a prod build the compiler might optimize that to a constant. I'm not 100% sure. But it's likely.
It's more likely with an array though. And even more likely if it's a const array
Yeah im thinking of switching some of my lists to arrays because they are completely constant, although some google searches had people saying theres almost no reason to use arrays over lists but i doubt that
Anyways, that's soo many "ifs" that you shouldn't rely on it.
It depends on the context. In most use cases you wouldn't be looping it tens of thousands of times
There is some overhead to lists no matter what. So there's gonna be a difference. Unless the compiler is smart enough to replace a list with an actual array, wich I'm doubtful about.
my main point though was wondering why/how those if statements arent in the build as if they were they would be very slow
Wdym? How do you know that they are not in the build?
build as in those if statements dont exist after compilation
How do you know that? And if they don't exist, what does?
as if they were the OldGenerateVertList section would be horribly slow
Why do you think so?
And i dont see any comparisons in the profiler
These would be part of the "self time", since these are not method calls
You can add markers around each of the if statements and you'll see that they are executed properly
ill try it
using (m_IFSTATEMENT.Auto())
{
if ((edgeTable[cubeindex] & 1) > 0)
i = 0;
}``` would this if statement show up in the profiler?
with m_IFSTATEMENT being the marker
It should, yes
*the marker would show up(with it's contents timing). Not the if statement itself
the if statement is a comparison so it should be shown taking time no?
with deep profiler*
I don't think so. I don't think basic operations are recorded individually.
The profiler works on a method basis
Or markers
so it does show up as op_Inequality
for inequality operator
I think i had some misunderstanding
For whatever reason i didnt even consider that im not removing the if statements, im just putting them in a for loop lol
Yep, that's pretty much what happens
It is interesting though that it is slightly slower in the for loop because of the array access
I wonder if i should use the for loop or just the continous if statements
maybe turn it into a switch
Honestly, I'd look at more effective optimization methods first.
for sure
Respected, I am using google play services.. for authentication and saving and load data feature of play services.. Should i need to add scope for these features in the google cloud platform.. if yes then how..? Please guide
hi
if you have a question then just ask
me?
can i ask you something
ok are you good at coding in unity
yes, most users here are
okay so you are saying you are good at coding in unity
yup
CAN WE START A DM
then... ask them here
good chance i'll make a mistake and someone else can correct me. that wont happen in DMs
no asking for !collab s here. besides, i dont really have the time to be a personal tutor
:loudspeaker: Collaborating and Job Posting
We do not accept job or collab posts on Discord.
Please, use Discussions to promote yourself as job-seeking, advertise commercial job offers, or look for non-commercial projects to participate in:
โข Collaboration & Jobs
not all the time just on week end it is just a project (game) if you do not want to help then fine
I completed a Udemy course for RPG Core. Finished the course, but the saving system was done using the Binary Formatter class which Microsoft has flagged as having severe security vulnerabilities. Therefore, there is another course that shows how to change the code using JSON. I use Unity Services and asking the experts here. What is a better way, if there is one, to write a saving system that works with Unity Services, like their DevOps? Are there packages in the Unity Asset store that sync with Unity Dev Ops? I would rather not write code from the ground up for an entire Saving System that works if someone far more crafty than I has already added it as a Plug-In?
I don't think there's anything remotely related to saving system in unity services.
Besides the core of a saving system would be heavily dependent on your project needs.
I figured as much. It really is a deep down core thing... I will probably have to rely on the JSON modifications. Yes, the implementation is coding in tight to the project. Does everyone basically write their own saving system? I wish there were more tutorials out there to help with this. What good is a game if you can't save the player's progres..
P.S. Just checked out your Slimeaccent game. Awesome. Great Job! Unique movement.
Hey guys I have a question for multiplayer using Mirror. So my game has 4 players max, but for any player other than the first and last player that joined, the game is always buggy such as enemies not being able to detect the other players and other features also not working for them. Some further context is that if ONLY 2 players join the game, it works perfectly, but if there are more than 2 players, it only works for the first player which is the host and the last player that joined. Thank you in advance guys!
Hey all, I'm really stuck with this hurdle. I've got a graph system that stores nodes (ID and position) and connections (node A and B it connects). I try to calculate my 'enclosed areas', but no matter what algoritm/approach I use, I keep getting duplicates/false areas or overlaps. Anyone knows how to begin tackling this?
this is probably an assignment problem, which is not solvable efficiently. You potentially have to compare each solution with all others to pick the correct ones.
i would look at algorithms to find all cycles in undirected graphs
then analyze these cycles to find the correct ones
if you cannot find out which cycles are correct because you lack the data to decide, your graph is potentially underspecified and the problem is not solvable. In your picture, the graph has the appearance of being solvable, but that appearance is data that is external to the data stored in the graph. You could potentially convert the graph into a triangle mesh, where you enforce the graph edges as triangle edges, then you can probably make decisions based on triangle/face adjacency.
Are you trying to calculate if a point is "inside" or "outside" of a closed loop?
I'm a little unclear
so, for example, the area enclosed by this cycle?
@compact ingot Thanks for the response! Ah alright. So this means I should consider user-assigned areas? Maybe a little less userfriendly but a quick and dirty option? The appearance of being solvable (but it not being solvable) probably explains why I broke my brain trying to solve it all day lol. The triangulation sounds interesting, I'll look into that!
@bleak citrus Correct, you could compare it to walls of a house (in 2D) and I need to know the rooms. Or roads and I need to know the city blocks.
The brute-force approach here would to be find all cycles in the graph, as Anikki suggested
Is this graph planar?
i.e. there are no crossing lines
The main difficulties I can see are dealing with:
- Cycles whose vertices are a superset of another cycle's vertices
- Cycles that enclose another cycle
for the first case, imagine a graph in the shape of an 8
There are three cycles in this graph: the upper half, the lower half, and the entire thing
I'm pretty sure you can simply discard any cycle that completely contains another cycle's vertices
The second case would be something like this. You'd need to subtract the inner cycle's area from the outer cycle's area. That seems a lot more difficult to reason about.
You would be able to create an ordering
you can solve the "is inside" problem by turning it into a mesh, algorithms exist, your only problem is that your rooms are not convex
So you'd first discard every cycle that is a superset of any other circle, then test every pair of cycles to decide if cycle A is enclosed by cycle B
Yeah, those were the things I kept running into. Duplicates or overlaps (enclosed/superset TIL!). Couldn't find a reliable way to filter that. The not being convex also threw me off.
I guess I chose too big of a hurdle lol. I'll dive into it and give it a try. You both game me some good insights. Thanks!
I tried this too, but imagine there is one node in the middle line of those two, now it's not detected anymore. It truly gives me a headache ๐ฅฒ
Like this?
Ah, yeah, you need a less strict criteria
Been a hot minute since I did graph theory in grad school, haha
I guess you could look at whether another cycle's vertices are either:
- In your own vertex set
- Enclosed inside your area
This is a more advanced example. I think I can prevent inside shapes with just the placement.
So I can maybe approach it like this:
- get a list of all nodes and connections
- trim nodes with less than 2 connections
- get all cycles
- stuck, lol
Or, out-of-the-box:
- get all nodes and connections
- find the shortest path to itself on every node (if no path = no area)
- remove duplicate areas
Oh that could also work with approach one. So a simple check if a node is inside it's area and if true, discard area?
well, "simple check" is doing a lot of heavy lifting there ๐
this has a lot of overlap with mesh generation
If you can triangulate the graph, it'll be trivial to decide if a point is inside of a cycle
since triangles are convex shapes
Oh that's what Anikki mentioned? I guess I'll dive into that then.
This brings me back to Blender tutorials lol. Triangulating Ngons and quads. But that way I could get my areas in the graph?
I'm writing a custom terrain system w/ an editor for my game and currently working on the detail painting system. The detail 'objects' are instanced geometry drawn via Graphics.DrawMeshInstancedIndirect.
When the user paints on the terrain, it adds to a list containing the type 'DetailObject', which looks like this:
public struct DetailObject
{
public Matrix4x4 trs;
public Vector3 normal;
public float normalOffset;
}
There is some extra processing (ensuring two details are too close, etc) and then the computebuffer that contains the data is released, and then recreated with the new data. I know this is a pretty bad way of updating a compute buffer, but I'm not really sure how to do it better. I know about basic concepts like using BeginWrite on the computebuffer, but I don't actually know how to use it and the documentation isn't any use.
Doing it this way causes the detail objects to flicker while painting due to the computebuffer being constantly released and recreated, which is distracting and ugly.
Here's what my update compute buffer code looks like:
public void UpdateDetailBuffer()
{
//After the newly painted detail objects are added to allDetail, this function is called.
if (mpb == null)
mpb = new MaterialPropertyBlock();
if (allDetail.Count == 0)
return;
//ToDo: Figure out how to use ComputeBuffer<T>.BeginWrite and ComputeBuffer<T>.EndWrite
detailBuffer?.Release();
detailBuffer = new ComputeBuffer(allDetail.Count, Marshal.SizeOf(typeof(DetailObject)));
detailBuffer.SetData(allDetail.ToArray());
mpb?.SetBuffer("_TerrainDetail", detailBuffer);
}
How can I rewrite this to use BeginWrite and EndWrite?
Actually, yeah, this is just a triangulation problem
Although, you have to know which face is which
which is part of your problem
There's got to be some prior art here
Can anyone help me? I can't figure out anything and there's zero useful information on how to use BeginWrite and EndWrite
for more clariy this is the issue I'm trying to fix
detail objects flicker as the user paints due to the computebuffer being deleted and recreated
Couldn't you just use SetData on an existing buffer
Instead of creating a new one
You have to have a precomputed size for a computebuffer, no?
If I have a ComputeBuffer that's storing 1000 detail objects and then paint 100 more and then try to add that data to the ComputeBuffer, I get an error
Make it big enough that you don't need to resize it or only need to rarely resize it
It's not uncommon to have a limit on the number of objects the user can place
You could also have it delete/overwrite the oldest objects when you reach the limit, like a ring buffer
got an interesting question, thought it was simple but apparently not so much
so I'm prepping this project for the asset store, and this asset generates code. I want it to generate it inside the folder of the asmdef of the asset just to not pollute the user's heirarchy, but at the same time i also don't know where exactly they're going to put this assembly.
So what I'm trying to do is determine (not runtime, at edit time) the root path of NisGab.asmdef, then from there just combine it with /Scripts/Generated/. anyone know how to do this?
you should be able to find the NisGab asm def asset with AssetDatabase.FindAssets()
You could also grab its guid and do guidtoassetpath
what would you filter in FindAssets to get it?
perhaps "NisGab t:AssemblyDefinition" ?
oh ok its literally just like the explorer filter neat
yea you can filter to most asset types like Texture2D or Prefab
hate that i have to put a magic string but if it work
well otherwise if you know the GUID of the asm def asset you can get the path directly with that
would the guid change if someone downloads and imports the asset tho
i dont think so
Asset guids are stored in the meta file, so as long as that is intact the guid won't change
ok i could try that
i have a compute shader question, I'm working on this 3D renderer that I can overlay onto my game to render lines in world space, you can see how it works here https://streamable.com/2eh7zh
basically using a compute shader I send a list of points from the CPU to the GPU, do the math to project it into 3D space, and I send it back to the CPU
then I send it to a second compute shader kernel that draws all the lines to the screen, and the result's in the video
I'm doing it like this because I was able to boost my performance by splitting up the task into two kernels that use threading differently, so I was basically able to double the amount of lines I could render without lagging
but would there be a way to handle this without having to send information back to the CPU in the middle of the calculation? that's still a big bottleneck in my system even though I was able to boost the performance a little
i'm technically not really gonna need to be able to render more lines than I can handle right now, I just want it to be able to lol
here's the relevant code
basically if possible I want to avoid having to juggle the information between the CPU and GPU bc that kinda defeats the purpose of using a compute shader in the first place, but I can't really think of a way to share information between kernels?
Why donโt you reuse the same buffer? That way you stop readingback?
CS.SetBuffer(1,โcalculatedBufferโ, buffer);
Get rid of the middle man
@bleak citrus @compact ingot : Thanks again for the help, wanted to let you guys know I found a solution. I couldn't quite grasp the triangulation but for now I brute-forced a solution, that kinda is an abstract way to do the triangulation.
I do the following:
- get a list of all cycles
- cycle holds a list of the nodes, each with a normalized/sorted string
- all duplicate strings get removed
- now we have a filtered list
- each cycle is now turned into a polygon
- a 'is point in polygon' check for each cycle with every node in the scene
- same again, but with the midpoints of each edge in the scene
- if one of the two above is true at any point, we remove the cycle
And now we have a list with all small cycles in our planar undirected graph. Maybe it can help someone else. ๐
nice
i get what you mean, but if I modify the buffer from the kernel does it modify it on the CPU side?
unless I'm wrong i thought the only way to get data back from the compute shader was to read it back into an array
It is. Yes, you need to read it back.
i did realize I don't actually need to be reading it back, in the first kernel i'm modifying the buffer anyway, so if I just dispatch the second kernel anyway it reads from the modified buffer on the GPU side
What you can do is bind the result buffer to the next compute shader directly, without reading it on the CPU side.
oop, exactly lol
now the only thing limiting performance is the shader itself which shouldn't be hard to test
One thing you should be careful about is race conditions though. If both shaders run anywhere close to each other, there's a chance that the second one would start reading the buffer before the first shader is done.
In this case, you should use a barrier.
mm right, how'd i do that?
like set a condition once the first one's done, and prevent the second one from running until the condition's met?
ah i see
No. That's something else(for syncing threads in one draw/dispatch call). The barrier command that I'm talking about needs to be called/queued on the CPU side.
Though, it's possible that unity does it itself under the hood. You'll need to test it out and see if you get any issues without a barrier.
From my experience thatโs not possible. The dispatch commands for compute shaders are put into the same command queue unless using a command buffer and the gpu is guaranteed to poll and complete a previous command before it attempts moving on to the next one in this queue. Either that or Unity underneath is adding a gpu fence after every dispatch
I donโt have any sources on this but from testing Iโve never had to ever consider race conditions like this
Also you could use renderprimitivesindirect to avoid reading back entirely unless you need it on the cpu for non-rendering reasons
Has anyone got any examples of Unity Jobs being used for marching squares? (and I mean specifically marching squares, not marching cubes)
For my custom terrain system, I'm using a modified version of the marching squares algorithm and I'm looking into moving the generation code to Unity Jobs.
It's pretty daunting and I'm struggling to figure out how to do it, but if there's any existing examples for Unity Jobs marching squares that already exist, it should help me a lot
there's a pretty good breakdown of the 3 main steps here: https://en.wikipedia.org/wiki/Marching_squares#Basic_algorithm
I think it would be pretty reasonable to make it as 3 jobs (one for each of those steps)
There's a reason I specifically ask for code examples because that's the main way I learn.
Because I do not fully understand the jobs API, I do not know what types can and cannot be used in a job. Having code available lets me immediately know what types I should be using
For example, I've been trying for the last hour to figure out how to write to a native list of Vector3 (vertex positions for my mesh) and I am blocked on a single error and after around 10 different pages of documentation I'm still not sure how I'm supposed to write mesh data in a job system
I'm not asking anyone to spoon feed me code, I'm simply asking if anyone knows of the existance of a github repo that contains jobs code for generating a mesh with marching squares
no code example but there are the docs about supported c# types for burst compilable code
scroll to C#/.NET Language Support
https://docs.unity.cn/Packages/com.unity.burst%401.3/manual/index.html
There are listed all the supported types.
you'll need to use the Unity.Mathematics library (the thread-safe one) and native arrays or something similar
EDIT: that is, the SIMD one with float3 rather than Vector3, etc
(I just mention this in case looking for Vector3s specifically is what's catching you up)
when you're to the point of making meshes, look up Mesh.AllocateWritableMeshData and Mesh.ApplyAndDisposeWritableMeshData in the docs, there's some example code in there
hey would anyone be able to help me out with a quick instantiation issue im having?
im using photon pun 2 by the way
:thinking: Asking Questions
:mag: Search the internet for your question!
:book: Use the API Scripting Reference and User Manual and this troubleshooting site for commonly posted issues.
:wrench: Attempt to debug your issue.
:thought_balloon: Find an appropriate channel by reading the name and description in #๐โfind-a-channel
:grey_question: And don't ask to ask, ask a full question illustrating with screenshots if needed.
-# For more posting guidelines, go to #854851968446365696
is this not where i ask for help?
Pay particular attention to the last few points
ahhhh
sorry about thatr
so im having an issue at the moment where if i were to start a game, then use another client to join said game all works fine. But if i were to leave and rejoin that same lobby i spawn and see an extra pair of arms with both my primary and secondary weapons, static, where i spawned, but this instance that did not happen and it spawned in a random location. im assuming its instantiating problems OR an issue with the clean up when i leave and rejoin, i just realized that when i rejoin the other clients dont the "player has joined the match" message.
ah alright, thank you
i need a tutorial on linking phones to unity to control
like this https://www.youtube.com/watch?v=7SbNYv01bGk&ab_channel=AmalJoy
As we know, mobile phones as already equipped with a number of sensors. This is a small prototype game which I made in Unity. In this project I have used mobile phone as a motion tracking input controller. The attempt was to make kinect like controller on zero budget. The sensor data from mobile is transferred to PC (Laptop) via wifi. After that...
specifically i need the phone's accelerometers
xyz
What you need is a tutorial on how to send data over lan. Im sure you will find one.
Then you can build a small unity app to run in the phone and send the data over
can you help me find that tutorial
I love how early 2000s this feels.
I'm going for that early 2000s feelings ๐
Huge fan of the older call of dutys, especially world at war so I'm hoping to make a game similar to that, just can't get past this speed bump
Ooh that's the coldest one haha nice choice of favorite
Makes for gritty gameplay haha
Yeah
Does UnityEvent<float> let you pass the value when I invoke in code to another function connected via inspector?
So far it only logs the value from inspector
yes? i think. UnityEvent<float> would pass the float value (passed when invoked) to the functions that are subscribed to it
Make sure you choose the "Dynamic" function from the top section
Not the "Constant" one where you enter in the float you want to pass
Oh it wasn't appearing at first or I'm blind
Honestly this is fantastic, I've been using Unity for years and never knew this was possible
But Godot does have a substantially better implementation with its signals.
Events exist in C# anyway, unity events are needed only for doing stuff via the inspector
99% of events I use are traditional events and any unity events are not subbed via the inspector either
I have a top down game, im procedurally tilting the character model based on input. but when i rotate the character model to say look left, and then i start moving, it tilts based on its rotation so clicking W which moves you up it would Yaw left instead of pitching down, how do i make it tilt based on world XYZ or even based on the Character Controller rotation which doesnt rotate?
Currently writing an indirect mesh renderer that spawns a bunch of the same model across generated terrain, with each terrain chunk having its own renderer. With the way it works right now, the rotation of every plant is only randomized to every renderer, so all of the plants in the same chunk have the same rotation. How would I fix this?
[BurstCompile]
private struct InitializeDataFrameMatrixJob : IJobParallelFor
{
[WriteOnly] public NativeArray<Matrix4x4> _transformMatrixArray;
[ReadOnly] public NativeArray<Vector3> _coordinates;
public void Execute(int index)
{
//Debug.Log(_coordinates[index]);
var random = new Unity.Mathematics.Random((uint)index + 1);
_transformMatrixArray[index] = Matrix4x4.TRS(_coordinates[index], Quaternion.Euler(-90, random.NextInt(0,360), 0), Vector3.one /** random.NextFloat(0.9f, 1.1f)*/);
}
}```
After running the job check the contents of the matrix array to see if rotations are randomized correctly. If they are, it's likely an issue with your shader or something else.
seems like they are, maybe? Not entirely sure how to tell
where does the random instance come from?
Random is a struct in Unity.Mathematics
so if you're passing it around to a bunch of threads they're all going to start with the same copied state
they're not going to be updating the state of a shared object somewhere
oh I'm a dummy it's being initialized right there
add some kind of unique id per plant to the job
you could use the InstanceID of the GameObject for example
then you would do:
var random = new Unity.Mathematics.Random((uint)index + 1 + plantId);```