Files
BoneSync/BoneSync/Data/ByteEncoder.cs
2025-07-24 00:25:01 +03:00

360 lines
9.7 KiB
C#

using BoneSync.Networking.Messages;
using StressLevelZero;
using StressLevelZero.Combat;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace BoneSync.Data
{
public static class BitPacking
{
public static byte[] PackBits(bool[] bits)
{
int byteCount = bits.Length / 8;
if (bits.Length % 8 != 0)
{
byteCount++;
}
byte[] bytes = new byte[byteCount];
for (int i = 0; i < bits.Length; i++)
{
int byteIndex = i / 8;
int bitIndex = i % 8;
if (bits[i])
{
bytes[byteIndex] |= (byte)(1 << bitIndex);
}
}
return bytes;
}
public static bool[] UnpackBits(byte[] bytes, int bitCount)
{
bool[] bits = new bool[bitCount];
for (int i = 0; i < bitCount; i++)
{
int byteIndex = i / 8;
int bitIndex = i % 8;
bits[i] = (bytes[byteIndex] & (1 << bitIndex)) != 0;
}
return bits;
}
}
internal class ByteEncoder
{
//public BinaryWriter writer;
//public BinaryReader reader;
public List<byte> Data;
public ByteEncoder()
{
Data = new List<byte>();
}
public ByteEncoder(byte[] data)
{
Data = data.ToList();
}
public byte[] ToArray()
{
return Data.ToArray();
}
public void SetBytes(byte[] data)
{
Data = data.ToList();
}
public void WriteByte(byte value)
{
Data.Add(value);
}
public void WriteBytes(byte[] value)
{
Data.AddRange(value);
}
public byte[] ReadBytes(int count)
{
if (Data.Count < count)
{
throw new Exception("Not enough data to read, expected " + count + " but only have " + Data.Count);
}
byte[] value = Data.GetRange(0, count).ToArray();
Data.RemoveRange(0, count);
return value;
}
public byte ReadByte()
{
byte value = Data[0];
Data.RemoveAt(0);
return value;
}
public void WriteBool(bool value)
{
WriteByte((byte)(value ? 1 : 0));
}
public bool ReadBool()
{
return ReadByte() == 1;
}
public void WriteInt(int value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public int ReadInt()
{
return BitConverter.ToInt32(ReadBytes(sizeof(int)), 0);
}
public void WriteLong(long value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public long ReadLong()
{
return BitConverter.ToInt64(ReadBytes(sizeof(long)), 0);
}
public void WriteFloat(float value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public float ReadFloat()
{
return BitConverter.ToSingle(ReadBytes(sizeof(float)), 0);
}
public void WriteUShort(ushort value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public ushort ReadUShort() {
return BitConverter.ToUInt16(ReadBytes(sizeof(ushort)), 0);
}
public void WriteDouble(double value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public double ReadDouble()
{
return BitConverter.ToDouble(ReadBytes(sizeof(double)), 0);
}
public void WriteString(string value)
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
WriteInt(bytes.Length);
WriteBytes(bytes);
}
public string ReadString()
{
int length = ReadInt();
return Encoding.UTF8.GetString(ReadBytes(length));
}
public void WriteULong(ulong value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public ulong ReadULong()
{
return BitConverter.ToUInt64(ReadBytes(sizeof(ulong)), 0);
}
public void WriteVector3(Vector3 value)
{
WriteFloat(value.x);
WriteFloat(value.y);
WriteFloat(value.z);
}
public Vector3 ReadVector3()
{
float x = ReadFloat();
float y = ReadFloat();
float z = ReadFloat();
return new Vector3(x, y, z);
}
public void WriteQuaternion(Quaternion value)
{
WriteVector3(value.eulerAngles);
}
public Quaternion ReadQuaternion()
{
Vector3 eulerAngles = ReadVector3();
return Quaternion.Euler(eulerAngles);
}
public void WriteSimpleTransform(SimpleSyncTransform value)
{
WriteVector3(value.position);
WriteQuaternion(value.rotation);
WriteBool(value.scale.HasValue);
if (value.scale.HasValue)
WriteVector3(value.scale.Value);
}
public SimpleSyncTransform ReadSimpleTransform()
{
Vector3 position = ReadVector3();
Quaternion rotation = ReadQuaternion();
bool hasScale = ReadBool();
Vector3? scale = null;
if (hasScale)
{
scale = ReadVector3();
}
return new SimpleSyncTransform()
{
position = position,
rotation = rotation,
scale = scale
};
}
public void WriteMatrix4x4(Matrix4x4 matrix)
{
for (int i = 0; i < 16; i++)
{
WriteFloat(matrix[i]);
}
}
public Matrix4x4 ReadMatrix4x4()
{
Matrix4x4 matrix = new Matrix4x4();
for (int i = 0; i < 16; i++)
{
matrix[i] = ReadFloat();
}
return matrix;
}
public void WriteBoolArray(bool[] array)
{
byte[] bytes = BitPacking.PackBits(array);
WriteByte((byte)bytes.Length);
WriteBytes(bytes);
}
public bool[] ReadBoolArray()
{
byte length = ReadByte();
byte[] bytes = ReadBytes(length);
return BitPacking.UnpackBits(bytes, length);
}
public void WriteAmmoVariables(AmmoVariables ammoVariables)
{
WriteBool(ammoVariables.Tracer);
WriteFloat(ammoVariables.ProjectileMass);
WriteFloat(ammoVariables.ExitVelocity);
WriteFloat(ammoVariables.AttackDamage);
WriteByte((byte)ammoVariables.AttackType);
WriteByte((byte)ammoVariables.cartridgeType);
}
public AmmoVariables ReadAmmoVariables()
{
AmmoVariables ammoVariables = new AmmoVariables()
{
Tracer = ReadBool(),
ProjectileMass = ReadFloat(),
ExitVelocity = ReadFloat(),
AttackDamage = ReadFloat(),
AttackType = (AttackType)ReadByte(),
cartridgeType = (Cart)ReadByte()
};
return ammoVariables;
}
public void WriteMagazineData(MagazineData magazineData)
{
WriteByte((byte)magazineData.weight);
WriteByte((byte)magazineData.platform);
WriteUShort((byte)magazineData.cartridgeType);
BulletObject[] bulletObjects = magazineData.AmmoSlots;
WriteByte((byte)bulletObjects.Length);
for (int i = 0; i < bulletObjects.Length; i++)
{
WriteAmmoVariables(bulletObjects[i].ammoVariables);
}
}
public MagazineData ReadMagazineData()
{
MagazineData mag = new MagazineData();
mag.weight = (Weight)ReadByte();
mag.platform = (Platform)ReadByte();
mag.cartridgeType = (Cart)ReadUShort();
byte bulletCount = ReadByte();
mag.AmmoSlots = new BulletObject[bulletCount];
for (int i = 0; i < bulletCount; i++)
{
mag.AmmoSlots[i] = new BulletObject()
{
ammoVariables = ReadAmmoVariables()
};
}
return mag;
}
public void WriteCompressedFloat(float value)
{
// write a float in the range of 0-1 with 2 decimal places
value = Mathf.Clamp01(value);
int rounded = Mathf.FloorToInt(value * 255f);
WriteByte((byte)rounded);
}
public float ReadCompressedFloat()
{
return ReadByte() / 255f;
}
public void WriteFingerCurl(SimpleFingerCurl fingerCurl)
{
WriteCompressedFloat(fingerCurl.thumb);
WriteCompressedFloat(fingerCurl.index);
WriteCompressedFloat(fingerCurl.middle);
WriteCompressedFloat(fingerCurl.ring);
WriteCompressedFloat(fingerCurl.pinky);
}
public SimpleFingerCurl ReadFingerCurl()
{
SimpleFingerCurl fingerCurl = new SimpleFingerCurl()
{
thumb = ReadCompressedFloat(),
index = ReadCompressedFloat(),
middle = ReadCompressedFloat(),
ring = ReadCompressedFloat(),
pinky = ReadCompressedFloat()
};
return fingerCurl;
}
}
}