I need recommendations for a Value type equivalent to array or list suitable for use in structs that will be used to store world state per tick of a game.
I have quite a few child transforms, of which, I'd like to store their rotation and position for syncing purposes over a network. I could do it via hardcoding each transforms position and rotation variable, but I'm wondering if there's a better way, such as storing them in a value type collection, suitable for use in structs.
#Value type equivalent to array or list suitable for use in structs that will be used to store state
1 messages · Page 1 of 1 (latest)
you would need to make your own struct, you can't make it variable-length.
oh actually, i think there is one
there's Span, but not quite sure how it works internally. might not be what you want
There's a couple options here, one of which is a fixed-size buffer, but that requires unsafe code.
One simple option is essentially a stupid struct with numbered values
struct MyFixedList {
public MyData data0;
public MyData data1;
// Etc
}```
Obviously you'd need a maximum count hardcoded here and you can make some helper accessors and such.
You can also use a fixed size NativeArray
Is the issue here that you need it to be a value type because your networking solution only supports serializing value types? Because otherwise, you should be able to use arrays and lists just fine in structs.
Otherwise, you can use Unity's native collections (i.e. NativeList etc), which is a value type with unmanaged memory backing it, but that comes with a few caveats around using it without leaking memory or crashing your game.
Tried this but unfortunately span seems to only work inline or via ref
I see so a struct that functions as a fixed size array with customized switch to access the hardcoded numbered variables
I'm not sure if I should be using list or array as the struct i'm implementing is for quick usage and will be dumped immediately after access.
Here's an example:
public struct PlayerStatePayload : IPayLoad
{
private int tick;
private byte objectID;
public Vector3 position;
public uint rotation;
public Vector3 weaponPosition;
public uint weaponRotation;
public Vector3 velocity;
public Vector3 angularVelocity;
public Span<Vector3> childTransformPositions;
public int Tick { get => tick; set => this.tick = value; }
public byte ObjectID { get => objectID; set => this.objectID = value; }
public Quaternion GetRot()
{
Quaternion rot = Quaternion.identity;
QuaternionCompressor.DecompressQuaternion(ref rot, rotation);
return rot;
}
public Quaternion GetEmitterRot()
{
Quaternion rot = Quaternion.identity;
QuaternionCompressor.DecompressQuaternion(ref rot, weaponRotation);
return rot;
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref objectID);
serializer.SerializeValue(ref position);
serializer.SerializeValue(ref rotation);
serializer.SerializeValue(ref velocity);
serializer.SerializeValue(ref angularVelocity);
serializer.SerializeValue(ref weaponRotation);
serializer.SerializeValue(ref weaponPosition);
}
}
It's mainly going to be used for player prediction and reconciliation
It does seem as though fixed sized native array / list would be one of the options https://docs.unity3d.com/6000.2/Documentation/ScriptReference/Unity.Collections.NativeArray_1.html#:~:text=NativeArray is a fixed-size,bounds%2C access%2C and dependencies.
Do I need to call Dispose myself once I've access the struct and would be done with it?
yeah - you can use an indexer to make it "feel" like an array too
i see, which is more performant?
yeah you need to dispose it when you're done with it unless you got it from somewhere that promises to dispose it
that's a complicated question
it depends 😜
It depends on the shape of your data, how big this "fixed" length is, how sparse the array is, the access patterns, how frequently it changes and needs to be synced, etc.
Oh basically this struct is for syncing gameobjects over the network, I want to remove NetworkTransform from all these 4 gameobjects which are child of the character. The struct will be used to send and receive position and rotation. So I don't think I will be changing the size of the array or changing the values once they are set
Maybe i should simply hardcode all these variables in the struct
Just to include other options, you can also use explicit struct layout and field offset to make space for a fixed number of elements and use unsafe to index into it. (not that I necessarily recommend you do it this way)
[StructLayout(LayoutKind.Explicit, Size = 64)]
public struct MyStruct
{
[FieldOffset(0)]
public int Number;
[FieldOffset(4)]
public Vector3 Vector;
[FieldOffset(16)]
private Vector3 childPositions;
public unsafe ref Vector3 this[int index]
{
get
{
if (index < 0 || index >= 4)
throw new ArgumentOutOfRangeException(nameof(index));
fixed(Vector3* position = &childPositions)
{
return ref UnsafeUtility.ArrayElementAsRef<Vector3>(position, index);
}
}
}
}
This is similar to fixed buffer, but that only supports built-in primitives, not structs like Vector3.