我想从我的独立WPF应用程序中的注册表中读取数据,该应用程序是在Unity上的游戏中使用PlayerPrefs创建的.问题是如何将float作为DWRD 32读取和写入注册表.

public static float Int64ToFloat(long value)
{
    byte[] bytes = BitConverter.GetBytes(value);
    byte[] floatBytes = new byte[4];
        
    Array.Copy(bytes, floatBytes, 4);

    if (BitConverter.IsLittleEndian)
                Array.Reverse(floatBytes);

    float floatValue = BitConverter.ToSingle(floatBytes, 0);

    return floatValue;
}

此代码返回极小的值,例如1.35E-43.

推荐答案

Unity拯救的不是float,而是double!这确实是一个很黑客的技巧,但如果你仔细观察,你会发现你的DWORD (32bit)确实包含一个64long!(不知道为什么他们没有正确 Select QWORD或直接在那里进行二进制)

正如针对浮点类型已经提到的那样,您不能简单地削减bytes并期望值保持与处理long - int相同.

你可以简单地使用

// Have in mind that the key here is NOT the one you use in Unity but also contains a certain trailing hash string
public static float GetFloat(string key, float fallback = 0f)
{
    using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(@"Software\Unity\UnityEditor\" + Application.companyName + "\\" + Application.productName))
    {
        var value = registryKey?.GetValue(key);
        if (value is long longValue)
        {                      
            // Convert the 64-bit value to a double
            var doubleValue = BitConverter.Int64BitsToDouble(longValue);
            // then simply cast to cut its precision down
            var floatValue = (float)doubleValue;
            return floatValue;
        }
    }

    return fallback;
}

供您验证

var input = 12345678901234567890.1234567890f;
PlayerPrefs.SetFloat("TestFloat", input);
var output = GetFloat("TestFloat_h1435782019");
Assert.AreApproximatelyEqual(input,output, "Value retrieved from registry does not match the value stored in PlayerPrefs.");

我刚刚也跌了this snippet

如果我们可以信任它,哈希字符串基本上计算为

public class PlayerPrefsHash
{
  // Returns the string property name Unity would generate for a player prefs registry key value 
  // e.g., "PlayerGold" -> "PlayerGold_hXXXXXXXXXXXXXX"
  public static string Hash(string name)
  {
    uint hash = 5381;
    foreach (char c in name)
      hash = hash * 33 ^ c;
    string key = name + "_h" + hash;
    return key;
  }
}

因此,您可以在我上面的方法中使用它,并且能够在Unity上使用与WPF端相同的键常数.

至少在我的快速测试中,它似乎是准确的

var key = PlayerPrefsHash.Hash("TestFloat");
Assert.AreEqual("TestFloat_h1435782019", key, "PlayerPrefsHash.Hash does not match PlayerPrefs generated hash.");

Csharp相关问答推荐

循环访问Android视图中动态创建的子视图

Blazor:计算值或保留为默认值

为什么EF Core 6会针对null验证Count(*)?

安装附加的. exe与Visual Studio

. NET JSON属性自定义所需逻辑

Blazor服务器端的身份验证角色

获取具有AutoFaces的所有IOptions对象的集合

在静态模式下实例化配置

C#和ASP.NET核心标识:提高GetUserAsync调用的性能

Swagger没有显示int?可以为空

如何管理Azure认证客户端响应和证书 fingerprint

我可以查看我们向应用程序洞察发送了多少数据吗?

为什么我的伺服电机不动,下面的代码?

如何将%{v_扩展}转换为%{v_扩展}>>

为什么我不能从我的异步任务方法中返回异步任务方法?

如何正确地在VB中初始化类?

项目参考和方法签名问题

使用ITfoxtec.Identity.Saml2解析相同键多值SAML 2声明

为什么我不能在固定语句中使用外部函数?

如何获取我在SQL中输入的值