C# 使用绝对最小位动态存储数值?

C# 使用绝对最小位动态存储数值?,c#,unity3d,networking,C#,Unity3d,Networking,我正在用C#/Unity制作一个游戏,希望最大限度地减少带宽使用。服务器每秒更新客户端十次,以更改单元位置。服务器仅在数据发生更改时发送数据,并且仅发送此记录值与上次记录值之间的差异;这可能是积极的,也可能是消极的。在任何时候都可能有从零到几千个单位的单位在使用 每个单位的默认数据是一个ushort和四个浮点变量(id、x、y、z、方向)。这将是18字节+对象(序列化)和数据报字节。现在我正在发送它,但它只是太多了,有一千个单位左右运行。。。18*10*1000=180kb/s 这可以简化为整数

我正在用C#/Unity制作一个游戏,希望最大限度地减少带宽使用。服务器每秒更新客户端十次,以更改单元位置。服务器仅在数据发生更改时发送数据,并且仅发送此记录值与上次记录值之间的差异;这可能是积极的,也可能是消极的。在任何时候都可能有从零到几千个单位的单位在使用

每个单位的默认数据是一个ushort和四个浮点变量(id、x、y、z、方向)。这将是18字节+对象(序列化)和数据报字节。现在我正在发送它,但它只是太多了,有一千个单位左右运行。。。18*10*1000=180kb/s

这可以简化为整数,因为我只关心精度的两个小数点。例如:13.35-13.10=0.25。。。我们可以存储为25。如果很多值将远小于255(一个字节),那么最好的解决方案将允许我们只动态存储所需的位加上尽可能少的开销。该解决方案还允许我们发送更大的值(如果需要)

这对于其他服务器命令很有用,比如对单位施加伤害,这需要id和伤害值。在大多数情况下,伤害值可能会小于20


使用C#如何以尽可能少的位动态存储网络传输所需的数据

编辑:增加了对负值的支持

我想你在找这样的东西:

公共静态UInt32组件(浮动dx、浮动dy、浮动dz)
{
//跟踪输入值是否为负值。
//如果他们是,让他们积极。
布尔ndx=假;
bool-ndy=false;
bool-ndz=false;
if(dx<0)
{
dx*=-1;
ndx=真;
}
if(dy<0)
{
dy*=-1;
ndy=真;
}
if(dz<0)
{
dz*=-1;
ndz=真;
}
//细分:
//
//(dx*100)
//取一个十进制值并将其缩放为整数值。因此0.25变为25。
//
//(内部)(dx*100)
//截断为整数。
//
//((整数)(dx*100)%100)
//如果这是4.25,那么应该是425。这只需要
//最后两位数字(mod 100)。
//这将进入最低的8位。
// 
//((int)(dy*100)%100)>16)/100;
//做同样的事情,但是用15-23位。
dx=(浮点)(输入&0x7f)/100;
dy=(浮点)((输入&0x7f00)>>8)/100;
dz=(浮点)(输入&0x7f0000)>>16)/100;
//如果设置了负值标志,则将其设为负值:
dx*=(输入和(uint)0x80)>1?-1f:1f;
dy*=(输入和(输出)0x8000)>1?-1f:1f;
dz*=(输入和(输出)0x800000)>1?-1f:1f;
}
正如您在这里看到的,此解决方案可能会产生舍入误差:

> var p = Pack(0.25f, -.67f, -0.12f);
> Unpack(p, out a, out b, out c);
> a
0.25
> b
-0.67
> c
-0.11
> 
(首先,我认为这可能是过早的优化。您是否绝对确定没有解决此问题的结构/体系结构方法?降低远程对象的更新率?等等?)

无论如何:

请不要立即排除这个想法(因为CPU的复杂性),但是你可能想考虑Zip和JPG格式是如何工作的。 我之所以提到这一点,是因为ZIP的基本工作原理是使用“可变长度”存储。它不是说“每个数据块是一个字节”,而是通过找出一种表示数据的好方法来压缩数据

假设我正在存储一个文本文件:

Seeeeeeeeeee meeeeeeeeeee leeeeeeeeeeeeeeeean freeeeeeeeeeeeeely.
。。。一个普通的文本文件每个字符需要一个字节,或520位。但是为什么?实际上,您可能希望该文件中的一个平均字符是“e”-如果您可以简单地使用一个位来表示“e”字符会怎么样? 如果第一位为“0”,则为“e”;否则,您必须读取更多的位来确定它是什么字符。可能是这样的:

0: 'e'
100: ' '
101: 'l'
11000: 'S'
11001: 'm'
11010: 'a'
11011: 'n'
11100: 'f'
11101: 'r'
11110: 'y'
11111: '.'
这根绳子需要多少空间?每个位上有52个e,每个位上有3个空格和2个l,每个位上有5个其他字符:52x1+5x3+8x5=107位。(有更好的方法压缩该字符串,但我尽量保持简单。)

这与你的问题有什么关系

你会有很多低值-越接近0,你越有可能看到它(你会有很多0-4的delta,而100-104的delta要少得多)。如果你希望大多数值都可以存储在4位中,为什么要用8位来存储大部分值呢

我不是说“在数据上调用zip库”(虽然这可能会奏效——我从未在小内存段上尝试过这样做,以了解它的时间密集程度)——但如果深入研究可变长度编码,您可能能够找到一个好的方案来使用这种方法表示数据

编辑:


。。。在我这边做了一些额外的谷歌搜索之后,您可能想看看System.IO.Compression.GZipStream。

“数据报”听起来像UDP。UDP不可靠。你认为只发送Delta是个好主意吗?还是定期同步?在进行位优化之前:您是否100%确定延迟是由带宽/网络吞吐量引起的?@Fildor很好,但在这种情况下,Unity的网络配置可以设置为可靠(我现在已经设置了),还有其他方法来解决此问题。然而,问题是,如果我们有1000个单位的修正,每18字节,每秒10次,那就是180kb/s。这是不能接受的。即使我们在顶部使用L4Z压缩,也只能将其减半。您应该添加适当的unity标记以更快地获得更好的答案。您的问题与传输大小无关。问题是如何组织游戏数据库以允许更新值。一旦你设计了更新过程,转换过程就会很简单。@jdweng我不明白,你能把任何阅读材料链接到exp吗