Generate deterministic UIDs for official songs + TJA, DLC compatibility
This commit is contained in:
parent
f65641ac5f
commit
25b558cdb9
85
TakoTako/MurmurHash2.cs
Normal file
85
TakoTako/MurmurHash2.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System.Text;
|
||||
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2017 Jitbit, 2022 TaikoMods contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
namespace TaikoMods;
|
||||
|
||||
public class MurmurHash2
|
||||
{
|
||||
public static uint Hash(string data)
|
||||
{
|
||||
return Hash(Encoding.UTF8.GetBytes(data));
|
||||
}
|
||||
|
||||
public static uint Hash(byte[] data)
|
||||
{
|
||||
return Hash(data, 0xc58f1a7a);
|
||||
}
|
||||
|
||||
private const uint m = 0x5bd1e995;
|
||||
private const int r = 24;
|
||||
|
||||
public static uint Hash(byte[] data, uint seed)
|
||||
{
|
||||
var length = data.Length;
|
||||
if (length == 0)
|
||||
return 0;
|
||||
var h = seed ^ (uint)length;
|
||||
var currentIndex = 0;
|
||||
while (length >= 4)
|
||||
{
|
||||
var k = (uint)(data[currentIndex++] | (data[currentIndex++] << 8) | (data[currentIndex++] << 16) |
|
||||
(data[currentIndex++] << 24));
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 3:
|
||||
h ^= (ushort)(data[currentIndex++] | (data[currentIndex++] << 8));
|
||||
h ^= (uint)(data[currentIndex] << 16);
|
||||
h *= m;
|
||||
break;
|
||||
case 2:
|
||||
h ^= (ushort)(data[currentIndex++] | (data[currentIndex] << 8));
|
||||
h *= m;
|
||||
break;
|
||||
case 1:
|
||||
h ^= data[currentIndex];
|
||||
h *= m;
|
||||
break;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ using System.Threading.Tasks;
|
||||
using BepInEx.Logging;
|
||||
using HarmonyLib;
|
||||
using Newtonsoft.Json;
|
||||
using TaikoMods;
|
||||
using TakoTako.Common;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
@ -372,24 +373,32 @@ public class MusicPatch
|
||||
song.genreNo = 7;
|
||||
}
|
||||
|
||||
var instanceId = Guid.NewGuid().ToString();
|
||||
if (isTjaSong)
|
||||
{
|
||||
song.id = song.songName?.text + song.songSubtitle?.text + song.songDetail?.text;
|
||||
if (string.IsNullOrEmpty(song.id))
|
||||
throw new Exception($"Song at {directory} does not have name, subtitle or detail text");
|
||||
|
||||
song.id += song.fumenOffsetPos + song.previewPos;
|
||||
}
|
||||
|
||||
song.SongName = song.id;
|
||||
song.FolderPath = directory;
|
||||
song.id = instanceId;
|
||||
|
||||
if (uniqueIdToSong.ContainsKey(song.uniqueId) || (song.uniqueId >= 0 && song.uniqueId <= SaveDataMax))
|
||||
// Clip off the last bit of the hash to make sure that the number is positive. This will lead to more collisions, but we should be fine.
|
||||
song.uniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF);
|
||||
if (song.uniqueId <= SaveDataMax)
|
||||
song.uniqueId += SaveDataMax;
|
||||
|
||||
if (uniqueIdToSong.ContainsKey(song.uniqueId))
|
||||
{
|
||||
var uniqueIdTest = unchecked(song.id.GetHashCode() + song.previewPos + song.fumenOffsetPos);
|
||||
while (uniqueIdToSong.ContainsKey(uniqueIdTest) || (uniqueIdTest >= 0 && uniqueIdTest <= SaveDataMax))
|
||||
uniqueIdTest = unchecked((uniqueIdTest + 1) * (uniqueIdTest + 1));
|
||||
|
||||
song.uniqueId = uniqueIdTest;
|
||||
throw new Exception($"Song \"{song.id}\" has collision with \"{uniqueIdToSong[song.uniqueId].id}\", bailing out...");
|
||||
}
|
||||
|
||||
customSongsList.Add(song);
|
||||
idToSong[song.id] = song;
|
||||
uniqueIdToSong[song.uniqueId] = song;
|
||||
Log.LogInfo($"Added {(isTjaSong ? "TJA" : "")} Song {song.songName.text}");
|
||||
Log.LogInfo($"Added{(isTjaSong ? " TJA" : "")} Song {song.songName.text}({song.uniqueId})");
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,10 +465,10 @@ public class MusicPatch
|
||||
$"song_{song.id}",
|
||||
song.order,
|
||||
song.genreNo,
|
||||
!Plugin.Instance.ConfigDisableCustomDLCSongs.Value,
|
||||
true, // We always want to mark songs as DLC, otherwise ranked games will be broken as you are gonna match songs that other people don't have
|
||||
false,
|
||||
0, false,
|
||||
0,
|
||||
2, // Always mark custom songs as "both players need to have this song to play it"
|
||||
new[]
|
||||
{
|
||||
song.branchEasy,
|
||||
@ -1287,83 +1296,6 @@ public class MusicPatch
|
||||
#pragma warning restore Harmony003
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow for a song id less than 0
|
||||
/// </summary>
|
||||
[HarmonyPatch(typeof(EnsoDataManager), "DecideSetting")]
|
||||
[HarmonyPrefix]
|
||||
public static bool DecideSetting_Prefix(EnsoDataManager __instance)
|
||||
{
|
||||
var ensoSettings = (EnsoData.Settings) typeof(EnsoDataManager).GetField("ensoSettings", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);
|
||||
// if (ensoSettings.musicuid.Length <= 0)
|
||||
// {
|
||||
// MusicDataInterface.MusicInfoAccesser infoByUniqueId = TaikoSingletonMonoBehaviour<CommonObjects>.Instance.MyDataManager.MusicData.GetInfoByUniqueId(ensoSettings.musicUniqueId);
|
||||
// if (infoByUniqueId != null)
|
||||
// {
|
||||
// ensoSettings.musicuid = infoByUniqueId.Id;
|
||||
// }
|
||||
// }
|
||||
// else if (ensoSettings.musicUniqueId <= DataConst.InvalidId)
|
||||
// {
|
||||
// MusicDataInterface.MusicInfoAccesser infoById = TaikoSingletonMonoBehaviour<CommonObjects>.Instance.MyDataManager.MusicData.GetInfoById(ensoSettings.musicuid);
|
||||
// if (infoById != null)
|
||||
// {
|
||||
// ensoSettings.musicUniqueId = infoById.UniqueId;
|
||||
// }
|
||||
// }
|
||||
if (ensoSettings.musicuid.Length <= 0 /* || ensoSettings.musicUniqueId <= DataConst.InvalidId*/)
|
||||
{
|
||||
List<MusicDataInterface.MusicInfoAccesser> musicInfoAccessers = TaikoSingletonMonoBehaviour<CommonObjects>.Instance.MyDataManager.MusicData.musicInfoAccessers;
|
||||
for (int i = 0; i < musicInfoAccessers.Count; i++)
|
||||
{
|
||||
if (!musicInfoAccessers[i].Debug)
|
||||
{
|
||||
ensoSettings.musicuid = musicInfoAccessers[i].Id;
|
||||
ensoSettings.musicUniqueId = musicInfoAccessers[i].UniqueId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MusicDataInterface.MusicInfoAccesser infoByUniqueId2 = TaikoSingletonMonoBehaviour<CommonObjects>.Instance.MyDataManager.MusicData.GetInfoByUniqueId(ensoSettings.musicUniqueId);
|
||||
if (infoByUniqueId2 != null)
|
||||
{
|
||||
ensoSettings.songFilePath = infoByUniqueId2.SongFileName;
|
||||
}
|
||||
|
||||
__instance.DecidePartsSetting();
|
||||
if (ensoSettings.ensoType == EnsoData.EnsoType.Normal)
|
||||
{
|
||||
int num = 0;
|
||||
int dlcType = 2;
|
||||
if (ensoSettings.rankMatchType == EnsoData.RankMatchType.None)
|
||||
{
|
||||
num = ((ensoSettings.playerNum != 1) ? 1 : 0);
|
||||
}
|
||||
else if (ensoSettings.rankMatchType == EnsoData.RankMatchType.RankMatch)
|
||||
{
|
||||
num = 2;
|
||||
ensoSettings.isRandomSelect = false;
|
||||
ensoSettings.isDailyBonus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
num = 3;
|
||||
ensoSettings.isRandomSelect = false;
|
||||
ensoSettings.isDailyBonus = false;
|
||||
}
|
||||
|
||||
TaikoSingletonMonoBehaviour<CommonObjects>.Instance.CosmosLib._kpiListCommon._musicKpiInfo.SetMusicSortSettings(num, dlcType, ensoSettings.isRandomSelect, ensoSettings.isDailyBonus);
|
||||
}
|
||||
else
|
||||
{
|
||||
ensoSettings.isRandomSelect = false;
|
||||
ensoSettings.isDailyBonus = false;
|
||||
}
|
||||
|
||||
typeof(EnsoDataManager).GetField("ensoSettings", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(__instance, ensoSettings);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read Fumen
|
||||
@ -1950,4 +1882,4 @@ public class MusicPatch
|
||||
public string FolderPath;
|
||||
public string SongName;
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@ namespace TakoTako
|
||||
public ConfigEntry<string> ConfigSongDirectory;
|
||||
public ConfigEntry<bool> ConfigSaveEnabled;
|
||||
public ConfigEntry<string> ConfigSaveDirectory;
|
||||
public ConfigEntry<bool> ConfigDisableCustomDLCSongs;
|
||||
public ConfigEntry<string> ConfigOverrideDefaultSongLanguage;
|
||||
public ConfigEntry<bool> ConfigApplyGenreOverride;
|
||||
|
||||
@ -64,12 +63,6 @@ namespace TakoTako
|
||||
$"{userFolder}/Documents/{typeof(Plugin).Namespace}/saves",
|
||||
"The directory where saves are stored");
|
||||
|
||||
ConfigDisableCustomDLCSongs = Config.Bind("CustomSongs",
|
||||
"DisableCustomDLCSongs",
|
||||
false,
|
||||
"By default, DLC is enabled for custom songs, this is to reduce any hiccups when playing online with other people. " +
|
||||
"Set this to true if you want DLC to be marked as false, be aware that the fact you're playing a custom song will be sent over the internet");
|
||||
|
||||
ConfigOverrideDefaultSongLanguage = Config.Bind("CustomSongs",
|
||||
"ConfigOverrideDefaultSongLanguage",
|
||||
string.Empty,
|
||||
@ -124,4 +117,4 @@ namespace TakoTako
|
||||
StartCoroutine(enumerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user