mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-12-08 13:08:26 +00:00
Merge d06c25a4b1 into 758f712eb5
This commit is contained in:
commit
ffd84abd66
|
|
@ -1117,6 +1117,9 @@ class Project extends HXProject
|
|||
{
|
||||
// This macro allows addition of new functionality to existing Flixel. -->
|
||||
addHaxeMacro("addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')");
|
||||
|
||||
// This macro will go over every song in the assets folder and store them in an array to check for cheated scores.
|
||||
addHaxeMacro("funkin.util.macro.SongDataValidator.loadSongData()");
|
||||
}
|
||||
|
||||
function configureOutputDir()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import funkin.play.song.ScriptedSong;
|
|||
import funkin.play.song.Song;
|
||||
import funkin.util.assets.DataAssets;
|
||||
import funkin.util.VersionUtil;
|
||||
import funkin.util.macro.SongDataValidator;
|
||||
import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ using funkin.data.song.migrator.SongDataMigrator;
|
|||
public override function loadEntries():Void
|
||||
{
|
||||
clearEntries();
|
||||
SongDataValidator.clearLists();
|
||||
|
||||
//
|
||||
// SCRIPTED ENTRIES
|
||||
|
|
@ -499,11 +501,16 @@ using funkin.data.song.migrator.SongDataMigrator;
|
|||
function loadEntryChartFile(id:String, ?variation:String):Null<JsonFile>
|
||||
{
|
||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||
|
||||
var entryFilePath:String = Paths.json('$dataFilePath/$id/$id-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}');
|
||||
if (!openfl.Assets.exists(entryFilePath)) return null;
|
||||
|
||||
var rawJson:String = openfl.Assets.getText(entryFilePath);
|
||||
if (rawJson == null) return null;
|
||||
|
||||
rawJson = rawJson.trim();
|
||||
SongDataValidator.checkChartValidity(rawJson, id, variation);
|
||||
|
||||
return {fileName: entryFilePath, contents: rawJson};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3380,8 +3380,9 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
var isNewHighscore = false;
|
||||
var prevScoreData:Null<SaveScoreData> = Save.instance.getSongScore(currentSong.id, suffixedDifficulty);
|
||||
var isChartValid:Bool = funkin.util.macro.SongDataValidator.isChartValid(currentSong.id, currentVariation);
|
||||
|
||||
if (currentSong != null && currentSong.validScore)
|
||||
if (currentSong != null && currentSong.validScore && isChartValid)
|
||||
{
|
||||
// crackhead double thingie, sets whether was new highscore, AND saves the song!
|
||||
var data =
|
||||
|
|
|
|||
|
|
@ -569,7 +569,8 @@ class ResultState extends MusicBeatSubState
|
|||
clearPercentCounter.curNumber = clearPercentTarget;
|
||||
|
||||
#if FEATURE_NEWGROUNDS
|
||||
var isScoreValid = !(params?.isPracticeMode ?? false) && !(params?.isBotPlayMode ?? false);
|
||||
var isChartValid:Bool = funkin.util.macro.SongDataValidator.isChartValid(params?.songId ?? "", params?.variationId ?? Constants.DEFAULT_VARIATION);
|
||||
var isScoreValid = !(params?.isPracticeMode ?? false) && !(params?.isBotPlayMode ?? false) && isChartValid;
|
||||
// This is the easiest spot to do the medal calculation lol.
|
||||
if (isScoreValid && clearPercentTarget == 69) Medals.award(Nice);
|
||||
#end
|
||||
|
|
|
|||
149
source/funkin/util/macro/SongDataValidator.hx
Normal file
149
source/funkin/util/macro/SongDataValidator.hx
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
package funkin.util.macro;
|
||||
|
||||
import haxe.crypto.Sha1;
|
||||
import haxe.rtti.Meta;
|
||||
#if macro
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.io.Path;
|
||||
import sys.FileSystem;
|
||||
#end
|
||||
|
||||
class SongDataValidator
|
||||
{
|
||||
static var _allCharts:Map<String, String> = null;
|
||||
static var _checkedCharts:Array<String> = [];
|
||||
static var _invalidCharts:Array<String> = [];
|
||||
|
||||
/**
|
||||
* See if the chart for the variation is valid, i.e. if the chart content differs from the compilation-time one.
|
||||
* If it isn't, add it to an array of invalid charts.
|
||||
* @param chartContent The content of the chart file.
|
||||
*/
|
||||
public static function checkChartValidity(chartContent:String, songId:String, variation:String = "default"):Void
|
||||
{
|
||||
var songFormat:String = '${songId}::${variation}';
|
||||
|
||||
// If the chart is already checked, do nothing.
|
||||
if (_checkedCharts.contains(songFormat)) return;
|
||||
|
||||
// If the all charts list is null, fetch it from the class' type.
|
||||
if (_allCharts == null)
|
||||
{
|
||||
var metaData:Dynamic = Meta.getType(SongDataValidator);
|
||||
|
||||
if (metaData.charts != null)
|
||||
{
|
||||
_allCharts = [];
|
||||
|
||||
for (element in (metaData.charts ?? []))
|
||||
{
|
||||
if (element.length != 2) throw 'Malformed element in chart datas: ' + element;
|
||||
|
||||
var song:String = element[0];
|
||||
var data:String = element[1];
|
||||
|
||||
_allCharts.set(song, data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw 'No chart datas found in SongDataValidator';
|
||||
}
|
||||
}
|
||||
|
||||
var isValid:Bool = false;
|
||||
|
||||
// If there is no chart found for the song and variation, it's a custom song and it should always be valid.
|
||||
if (!_allCharts.exists(songFormat))
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if the content matches.
|
||||
var chartClean:String = Sha1.encode(chartContent);
|
||||
if (chartClean == _allCharts.get(songFormat)) isValid = true;
|
||||
}
|
||||
|
||||
// Add to an array if the chart is invalid.
|
||||
if (!isValid)
|
||||
{
|
||||
trace(' [WARN] The chart file for the song $songId and variation $variation has been tampered with.');
|
||||
_invalidCharts.push(songFormat);
|
||||
}
|
||||
|
||||
// Add the song to the checked charts so that we don't have to run checks again.
|
||||
_checkedCharts.push(songFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the chart isn't in the invalid charts list.
|
||||
*/
|
||||
public static function isChartValid(songId:String, variation:String = "default"):Bool
|
||||
{
|
||||
return !_invalidCharts.contains('${songId}::${variation}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the lists so we can check for songs again.
|
||||
*/
|
||||
public static function clearLists():Void
|
||||
{
|
||||
_checkedCharts = [];
|
||||
_invalidCharts = [];
|
||||
}
|
||||
|
||||
#if macro
|
||||
public static inline final BASE_PATH:String = "assets/preload/data/songs";
|
||||
|
||||
static var calledBefore:Bool = false;
|
||||
#end
|
||||
|
||||
public static macro function loadSongData():Void
|
||||
{
|
||||
Context.onAfterTyping(function(_) {
|
||||
if (calledBefore) return;
|
||||
calledBefore = true;
|
||||
|
||||
var allCharts:Array<Expr> = [];
|
||||
|
||||
// Load songs from the assets folder.
|
||||
var songs:Array<String> = FileSystem.readDirectory(BASE_PATH);
|
||||
for (song in songs)
|
||||
{
|
||||
var songFiles:Array<String> = FileSystem.readDirectory(Path.join([BASE_PATH, song]));
|
||||
for (file in songFiles)
|
||||
{
|
||||
if (!StringTools.endsWith(file, ".json")) continue; // Exclude non-json files.
|
||||
|
||||
var splitter:Array<String> = StringTools.replace(file, ".json", "").split("-");
|
||||
|
||||
if (splitter[1] != "chart") continue; // Exclude non-chart files.
|
||||
|
||||
var variation:String = splitter[2] ?? "default";
|
||||
var chart:String = sys.io.File.getContent(Path.join([BASE_PATH, song, file]));
|
||||
|
||||
chart = Sha1.encode(StringTools.trim(chart));
|
||||
|
||||
var entry = [macro $v{'${song}::${variation}'}, macro $v{chart}];
|
||||
|
||||
allCharts.push(macro $a{entry});
|
||||
}
|
||||
}
|
||||
|
||||
// Add the chart data to the class.
|
||||
var dataClass = Context.getType('funkin.util.macro.SongDataValidator');
|
||||
|
||||
switch (dataClass)
|
||||
{
|
||||
case TInst(t, _):
|
||||
var dataClassType = t.get();
|
||||
dataClassType.meta.remove('charts');
|
||||
dataClassType.meta.add('charts', allCharts, Context.currentPos());
|
||||
default:
|
||||
throw 'Could not find SongDataValidator type';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue