没有这方面的文档。
我了解到Murmur2用于散列东西(也没有在任何地方提到..)
但我不完全知道如何对插件进行哈希处理。 我是否需要对文件名、内容、什么内容、所有内容、按什么顺序进行哈希处理?
有人可以详细说明一个简单的示例插件吗?
_retail_/Interface/Addons/AutoRepair/
.rw-rw-r-- 2.3k marco 9 Mar 20:22 AutoRepair.lua
.rw-rw-r-- 249 marco 9 Mar 20:22 AutoRepair.toc
.rw-rw-r-- 371 marco 9 Mar 20:22 AutoRepair.xml
需要做什么才能获取指纹哈希并将其发送到 CF API 以获得与 mod 的精确匹配?
我当前的方法是对文件的内容进行哈希处理,将这些指纹按升序排序,按该顺序将它们附加到字符串中,然后对该字符串进行哈希处理以获得最终的指纹。
但是,当使用该指纹查询 API 时,这并没有取得任何成功。
package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"strconv"
"strings"
"github.com/joho/godotenv"
mm "github.com/mistweaverco/go-murmur/murmur2"
)
func ReadFileAsBytes(path string) []byte {
b, err := os.ReadFile(path)
if err != nil {
panic(err)
}
return b
}
func GetFileListRecursive(dir string) []string {
files := []string{}
fileInfos, err := ioutil.ReadDir(dir)
if err != nil {
log.Fatal(err)
}
for _, fileInfo := range fileInfos {
if fileInfo.IsDir() {
files = append(files, GetFileListRecursive(dir+fileInfo.Name()+"/")...)
} else {
files = append(files, dir+fileInfo.Name())
}
}
return files
}
type Fingerprint struct {
Title string
Hash string
Modified int64
AddonDir string
Fingerprint uint32
}
func GetFingerprint(addonDir string) Fingerprint {
fingerprint := Fingerprint{}
fingerprint.AddonDir = addonDir
fullAddonDir := wowDirPrefix + "/Interface/Addons/" + addonDir + "/"
toFingerprint := []string{}
fingerprints := []uint32{}
files := GetFileListRecursive(fullAddonDir)
for _, file := range files {
if strings.HasSuffix(file, ".lua") || strings.HasSuffix(file, ".toc") || strings.HasSuffix(file, ".xml") {
toFingerprint = append(toFingerprint, file)
}
}
sort.Strings(toFingerprint)
fmt.Println(toFingerprint)
for _, s := range toFingerprint {
fc := ReadFileAsBytes(s)
fingerprints = append(fingerprints, mm.MurmurHash2(fc, 1))
}
compositeFingerprint := ""
sort.Slice(fingerprints, func(i, j int) bool { return fingerprints[i] < fingerprints[j] })
fmt.Println(fingerprints)
for _, f := range fingerprints {
compositeFingerprint += strconv.Itoa(int(f))
}
fmt.Println(compositeFingerprint)
fingerprint.Fingerprint = mm.MurmurHash2([]byte(compositeFingerprint), 1)
return fingerprint
}
func env(k string, failOnMissing bool) string {
value := os.Getenv(k)
if value != "" {
return value
}
if failOnMissing {
log.Fatalf("%v environment variable is not set.", k)
}
return ""
}
func main() {
godotenv.Load()
wowDirPrefix = env("DEBUG_WOW_RETAIL_DIR", false)
fp := GetFingerprint("AutoRepair")
fmt.Println(fp)
}
程序的输出看起来像这样:
[Interface/Addons/AutoRepair/AutoRepair.lua Interface/Addons/AutoRepair/AutoRepair.toc Interface/Addons/AutoRepair/AutoRepair.xml]
[1276060341 2556314513 2805448843]
127606034125563145132805448843
{ 0 AutoRepair 1798771541}
使用该输出,最终计算出的指纹是
1798771541
,但是使用该指纹查询 API 不会产生任何结果,而它应该产生 AutoRepair
插件。
有一个算法的 C++ 实现似乎可以在这里工作:https://github.com/meza/curseforge-fingerprint/blob/b15012c026c56ca89fad90f8cf9a8e140616e2c0/src/addon/fingerprint.cpp#L36-L90.
我在一些文件(不是《魔兽世界》,而是《我的世界》)上进行了测试,当提供给 HTTP API 时,得到了所需的结果。
Go 的 1:1 翻译:
func isWhiteSpace(b byte) bool {
return b == '\t' || b == '\n' || b == '\r' || b == ' '
}
func computeCurseForgeFingerprintNormalizedLength(buf *bytes.Buffer) int {
var len_no_whitespace int = 0
bytes := buf.Bytes()
for i := 0; i < buf.Len(); i++ {
char := bytes[i]
if !isWhiteSpace(char) {
len_no_whitespace++
}
}
return len_no_whitespace
}
// https://github.com/meza/curseforge-fingerprint/blob/b15012c026c56ca89fad90f8cf9a8e140616e2c0/src/addon/fingerprint.cpp#L36-L90
func CalculateCurseForgeFingerprint(buf *bytes.Buffer) uint32 {
const multiplex = 1540483477
len := buf.Len()
bytes := buf.Bytes()
var num1 uint32 = uint32(computeCurseForgeFingerprintNormalizedLength(buf))
var num2 uint32 = 1 ^ num1
var num3 uint32 = 0
var num4 uint32 = 0
for i := 0; i < len; i++ {
b := bytes[i]
if !isWhiteSpace(b) {
num3 |= uint32(b) << num4
num4 += 8
if num4 == 32 {
var num6 uint32 = num3 * multiplex
var num7 uint32 = (num6 ^ num6>>24) * multiplex
num2 = num2*multiplex ^ num7
num3 = 0
num4 = 0
}
}
}
if num4 > 0 {
num2 = (num2 ^ num3) * multiplex
}
num6 := (num2 ^ num2>>13) * multiplex
return num6 ^ num6>>15
}