move some scripts from art/ submodule to main funkin repo
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package art;
|
||||
|
||||
using DateTools;
|
||||
|
||||
class Postbuild
|
||||
{
|
||||
static function main()
|
||||
{
|
||||
/* trace('creating NG zip');
|
||||
var binFolder:String = 'export/release/html5/bin/';
|
||||
|
||||
var date = Date.now();
|
||||
var outputName:String = 'NG-' + date.format("%Y%m%d--%H%M") + '.zip';
|
||||
|
||||
var out = sys.io.File.write(outputName);
|
||||
var zip = new haxe.zip.Writer(out);
|
||||
zip.write(getEntries(binFolder));
|
||||
trace('Finished creating ZIP');
|
||||
*/
|
||||
}
|
||||
|
||||
static function getEntries(dir:String, entries:List<haxe.zip.Entry> = null, inDir:Null<String> = null)
|
||||
{
|
||||
if (entries == null) entries = new List<haxe.zip.Entry>();
|
||||
if (inDir == null) inDir = dir;
|
||||
|
||||
for (file in sys.FileSystem.readDirectory(dir))
|
||||
{
|
||||
var path = haxe.io.Path.join([dir, file]);
|
||||
if (sys.FileSystem.isDirectory(path)) getEntries(path, entries, inDir);
|
||||
else
|
||||
{
|
||||
var bytes:haxe.io.Bytes = haxe.io.Bytes.ofData(sys.io.File.getBytes(path).getData());
|
||||
var entry:haxe.zip.Entry =
|
||||
{
|
||||
fileName: StringTools.replace(path, inDir, ""),
|
||||
fileSize: bytes.length,
|
||||
fileTime: Date.now(),
|
||||
compressed: false,
|
||||
dataSize: sys.FileSystem.stat(path).size,
|
||||
data: bytes,
|
||||
crc32: haxe.crypto.Crc32.make(bytes)
|
||||
};
|
||||
entries.push(entry);
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import haxe.Json;
|
||||
import haxe.Log;
|
||||
import haxe.macro.Compiler;
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
|
||||
using StringTools;
|
||||
|
||||
#if !interp
|
||||
package art;
|
||||
|
||||
// needs this thing to be run by interp, just for me lol!
|
||||
#end
|
||||
// general use of this!!
|
||||
// if run in INTERP MODE:
|
||||
// - art>haxe --main SongConverter --interp
|
||||
// - song to convert: ../assets/preload/data/
|
||||
// it will run through EVERY folder in there and convert the old songs to the new format!
|
||||
// TODO make instructions for the C# script version!
|
||||
class SongConverter
|
||||
{
|
||||
public static var VERSION:String = '0.1.0';
|
||||
|
||||
// TODO
|
||||
// Update engine shit, to accomodate single file
|
||||
static function main()
|
||||
{
|
||||
// trace(Compiler.get);
|
||||
// trace(Compiler.getDefine('sysfsd'));
|
||||
|
||||
Sys.stdout().writeString('Please type directory you want to convert: ');
|
||||
Sys.stdout().flush();
|
||||
final input = Sys.stdin().readLine();
|
||||
trace('Hello ${input}!');
|
||||
|
||||
/* Sys.stdout().writeString('What type of conversion do you need?\n\t0: Old charts to new chart\n\t1: new chart to .... new chart? lol\n>');
|
||||
Sys.stdout().flush();
|
||||
final deleteShitIDK = Std.parseInt(Sys.stdin().readLine());
|
||||
|
||||
trace(deleteShitIDK); */
|
||||
|
||||
var songCount:Int = 0;
|
||||
|
||||
for (fileThing in FileSystem.readDirectory('${input}/.'))
|
||||
{
|
||||
// trace(fileThing);
|
||||
// trace(FileSystem.isDirectory(${input} + "/" + fileThing));
|
||||
|
||||
if (FileSystem.isDirectory(${input} + "/" + fileThing) && fileThing.toLowerCase() != 'smash')
|
||||
{
|
||||
trace('Formatting $fileThing');
|
||||
formatSongs(fileThing, input);
|
||||
|
||||
songCount++;
|
||||
}
|
||||
}
|
||||
|
||||
trace('CONVERTED $songCount SONGS!!');
|
||||
|
||||
var timer:Int = 5;
|
||||
|
||||
while (timer > 0)
|
||||
{
|
||||
Sys.stdout().writeString('CLOSING IN $timer SECONDS!');
|
||||
Sys.sleep(1);
|
||||
Sys.print("\r");
|
||||
timer -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static function formatSongs(songName:String, root:String)
|
||||
{
|
||||
var existsArray:Array<Bool> = [];
|
||||
|
||||
var songMap:Map<String, Dynamic> = new Map();
|
||||
var speedMap:Map<String, Dynamic> = new Map();
|
||||
|
||||
for (songFile in FileSystem.readDirectory('$root/$songName/'))
|
||||
{
|
||||
if (!songFile.endsWith('json') || !songFile.startsWith(songName)) continue; // ACCOMODATE FOR PICO SPEAKER EVENTUALLY!
|
||||
|
||||
var funnyFile:Dynamic = cast Json.parse(File.getContent('$root/$songName/$songFile'));
|
||||
|
||||
var songSplit:Array<String> = songFile.split('-');
|
||||
var songShit:String = 'normal';
|
||||
|
||||
if (songSplit.length > 1)
|
||||
{
|
||||
if (songSplit[1] == 'new.json')
|
||||
{
|
||||
FileSystem.deleteFile('$root/$songName/$songFile');
|
||||
trace('DELETEING $songFile');
|
||||
continue;
|
||||
}
|
||||
|
||||
songShit = songSplit[1].substr(0, songSplit[1].length - 5);
|
||||
}
|
||||
|
||||
if (songShit != 'normal')
|
||||
{
|
||||
songMap[songShit] = funnyFile.song.notes;
|
||||
speedMap[songShit] = funnyFile.song.speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
|
||||
if (funnyFile.song.notes is Array)
|
||||
{
|
||||
songMap[songShit] = funnyFile.song.notes[1];
|
||||
speedMap[songShit] = funnyFile.song.speed[1];
|
||||
}
|
||||
else if (Type.typeof(funnyFile.song.notes) == TObject)
|
||||
{
|
||||
var dipshitMap:Map<String, Dynamic> = cast funnyFile.song.notes;
|
||||
|
||||
// songMap[songShit] = dipshitMap.get('normal');
|
||||
}
|
||||
else
|
||||
{
|
||||
songMap[songShit] = funnyFile.song.notes;
|
||||
speedMap[songShit] = funnyFile.song.speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fileNormal:Dynamic = cast Json.parse(File.getContent('$root/$songName/$songName.json'));
|
||||
|
||||
fileNormal.song.notes = songMap;
|
||||
fileNormal.song.speed = speedMap;
|
||||
|
||||
fileNormal.song.hasDialogueFile = false;
|
||||
fileNormal.song.stageDefault = getStage(songName);
|
||||
|
||||
fileNormal.version = 'FNF SongConverter $VERSION';
|
||||
|
||||
var daJson = Json.stringify(fileNormal, null, "\t");
|
||||
// trace(daJson);
|
||||
File.saveContent('$root/$songName/$songName.json', daJson);
|
||||
}
|
||||
|
||||
static function noteCleaner(notes:Array<Dynamic>):Array<Dynamic>
|
||||
{
|
||||
var swagArray:Array<Dynamic> = [];
|
||||
for (i in notes)
|
||||
{
|
||||
if (i.sectionNotes.length > 0) swagArray.push(i);
|
||||
}
|
||||
|
||||
return swagArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quicky lil function just for me formatting the old songs hehehe
|
||||
*/
|
||||
static function getStage(songName:String):String
|
||||
{
|
||||
switch (songName)
|
||||
{
|
||||
case 'spookeez' | 'monster' | 'south':
|
||||
return "spooky";
|
||||
case 'pico' | 'blammed' | 'philly':
|
||||
return 'philly';
|
||||
case "milf" | 'satin-panties' | 'high':
|
||||
return 'limo';
|
||||
case "cocoa" | 'eggnog':
|
||||
return 'mall';
|
||||
case 'winter-horrorland':
|
||||
return 'mallEvil';
|
||||
case 'senpai' | 'roses':
|
||||
return 'school';
|
||||
case 'thorns':
|
||||
return 'schoolEvil';
|
||||
case 'guns' | 'stress' | 'ugh':
|
||||
return 'tank';
|
||||
default:
|
||||
return 'stage';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import csv
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
# This script imports a CSV file, and bulk updates the chart metadata files
|
||||
#
|
||||
# Requirements:
|
||||
# python3 I believe
|
||||
# and you need to have npm/npx, as we use that to run prettier to keep the same formatting
|
||||
#
|
||||
# Usage:
|
||||
# In our Google Sheets, export as .csv file
|
||||
#
|
||||
# Then in here from within this directory, run:
|
||||
# python3 sheetsToCharts.py path/to/csv/file.csv
|
||||
#
|
||||
# use from within this directory, as the paths to the chart metadata files are relative to this directory
|
||||
|
||||
|
||||
# Get the command line argument, if one wasn't already provided
|
||||
if len(sys.argv) < 2:
|
||||
csv_file = input("Please provide the CSV file path: ")
|
||||
else:
|
||||
csv_file = sys.argv[1]
|
||||
|
||||
# Open the CSV file
|
||||
with open(csv_file, 'r') as file:
|
||||
reader = csv.reader(file)
|
||||
|
||||
# Which rows for each difficulty are we looking for
|
||||
diff_rows = {}
|
||||
|
||||
# Iterate over each row in the CSV file
|
||||
for idx, row in enumerate(reader):
|
||||
|
||||
# The first row has headers for the columns, stuff like "Easy - Difficulty", so we want
|
||||
# to know which rows corresponde to which difficulty
|
||||
if idx == 0:
|
||||
pattern = r"\b(?:difficulty)\b"
|
||||
|
||||
diff_cols = []
|
||||
diff_words = []
|
||||
|
||||
# Go through each column, and see if it includes the word "difficulty"
|
||||
# then append the column index, and the first word of the column (usually what difficulty it is, "easy", "normal", "hard", etc.)
|
||||
for colindex, column in enumerate(row):
|
||||
txt = re.findall(pattern, column, flags=re.IGNORECASE)
|
||||
if txt:
|
||||
diff_cols.append(colindex)
|
||||
diff_words.append(column.split()[0].lower())
|
||||
|
||||
# We then create a dictionary for use later, where the key is the difficulty, and the value is the column index
|
||||
diff_rows = dict(zip(diff_words, diff_cols))
|
||||
else:
|
||||
# Some song title parsing, to match the filenames we used in for the chart files
|
||||
song_title = row[1].lower() # we use lowercase for filenames, SOUTH -> south
|
||||
song_title = song_title.replace(" ", "-") # usually we change spaces to dashes, PHILLY NICE -> philly-nice
|
||||
song_title = song_title.replace(".", "") # M.I.L.F. -> milf
|
||||
song_title = song_title.replace("'", "") # blazin' -> blazin
|
||||
|
||||
# we open the chart metadata json file for writing and reading ("r+")
|
||||
with open(f"../../../assets/preload/data/songs/{song_title}/{song_title}-metadata.json", "r+") as chart_metadata_file:
|
||||
|
||||
json_data = json.load(chart_metadata_file) # load the file as a python data structure/dict
|
||||
play_data = json_data["playData"] # we want to modify the "playData" section, as that holds the difficulty
|
||||
|
||||
# note to self, python equals(=) operator seems to create a reference for the variable,
|
||||
# so modifying play_data will also modify json_data, so we can save json_data easily later
|
||||
|
||||
# if the chart metadata file doesn't already have a "ratings" dict/section, we create one here with 0 for each
|
||||
if "ratings" not in play_data:
|
||||
play_data["ratings"] = {'easy': 0, 'normal': 0, 'hard': 0}
|
||||
|
||||
ratings = play_data["ratings"]
|
||||
|
||||
# Now we go through our data from the csv file, and the data we kept from the columns there
|
||||
# will be put into our new ratings var, if it exists
|
||||
for diff, col in diff_rows.items():
|
||||
if row[col] == "":
|
||||
continue
|
||||
if diff in ratings:
|
||||
ratings[diff] = round(float(row[col])) # convert the string to a float, and then round it to nearest int
|
||||
|
||||
# Convert the python json_data dict back to a json string
|
||||
json_output = json.dumps(json_data)
|
||||
|
||||
# Write the json string back to the file, and truncate the rest of the file
|
||||
chart_metadata_file.seek(0)
|
||||
chart_metadata_file.write(json_output)
|
||||
chart_metadata_file.truncate()
|
||||
chart_metadata_file.close()
|
||||
|
||||
# Bit hacky, but we simply run `npx prettier` using the same rules we use for FNF here
|
||||
# essnetially running it via cli and passing in the songs folder and our prettier config file
|
||||
# This should make the spacing and formatting consistent
|
||||
command = "npx prettier ../../../assets/preload/data/songs --write --config ../../../.prettierrc.js"
|
||||
subprocess.run(command, shell=True)
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find all files in OGG format and execute ffmpeg to convert them to MP3
|
||||
# Skips files that are already in MP3 format
|
||||
find "../assets/" -name "*.ogg" -exec sh -c 'ffmpeg -n -i {} "${0%.*}.mp3"' {} \;
|
||||
@@ -0,0 +1,218 @@
|
||||
import requests
|
||||
import sys
|
||||
|
||||
PROJECT_ID = 5582053
|
||||
|
||||
TEMPLATE = 'jQuery("#new-event-name").val("{event}"); jQuery("#save-new-event").click();'
|
||||
|
||||
EVENT_TEMPLATES = [
|
||||
"start-game",
|
||||
"watch-cartoon",
|
||||
"open-credits",
|
||||
|
||||
"start-song_{songId}-{variation}",
|
||||
"blueballs_{songId}-{variation}",
|
||||
"complete-song_{songId}-{variation}",
|
||||
"start-level_{levelId}",
|
||||
"complete-level_{levelId}",
|
||||
"earn-rank_{rankName}",
|
||||
]
|
||||
|
||||
SONG_IDS = [
|
||||
{ "songId": "tutorial", "variation": "default" },
|
||||
{ "songId": "tutorial", "variation": "erect" },
|
||||
{ "songId": "tutorial", "variation": "pico" },
|
||||
|
||||
{ "songId": "bopeebo", "variation": "default" },
|
||||
{ "songId": "bopeebo", "variation": "erect" },
|
||||
{ "songId": "bopeebo", "variation": "pico" },
|
||||
|
||||
{ "songId": "fresh", "variation": "default" },
|
||||
{ "songId": "fresh", "variation": "erect" },
|
||||
{ "songId": "fresh", "variation": "pico" },
|
||||
|
||||
{ "songId": "dadbattle", "variation": "default" },
|
||||
{ "songId": "dadbattle", "variation": "erect" },
|
||||
{ "songId": "dadbattle", "variation": "pico" },
|
||||
|
||||
{ "songId": "spookeez", "variation": "default" },
|
||||
{ "songId": "spookeez", "variation": "erect" },
|
||||
{ "songId": "spookeez", "variation": "pico" },
|
||||
|
||||
{ "songId": "south", "variation": "default" },
|
||||
{ "songId": "south", "variation": "erect" },
|
||||
{ "songId": "south", "variation": "pico" },
|
||||
|
||||
{ "songId": "monster", "variation": "default" },
|
||||
{ "songId": "monster", "variation": "erect" },
|
||||
{ "songId": "monster", "variation": "pico" },
|
||||
|
||||
{ "songId": "pico", "variation": "default" },
|
||||
{ "songId": "pico", "variation": "erect" },
|
||||
{ "songId": "pico", "variation": "pico" },
|
||||
|
||||
{ "songId": "philly-nice", "variation": "default" },
|
||||
{ "songId": "philly-nice", "variation": "erect" },
|
||||
{ "songId": "philly-nice", "variation": "pico" },
|
||||
|
||||
{ "songId": "blammed", "variation": "default" },
|
||||
{ "songId": "blammed", "variation": "erect" },
|
||||
{ "songId": "blammed", "variation": "pico" },
|
||||
|
||||
{ "songId": "satin-panties", "variation": "default" },
|
||||
{ "songId": "satin-panties", "variation": "erect" },
|
||||
{ "songId": "satin-panties", "variation": "pico" },
|
||||
|
||||
{ "songId": "high", "variation": "default" },
|
||||
{ "songId": "high", "variation": "erect" },
|
||||
{ "songId": "high", "variation": "pico" },
|
||||
|
||||
{ "songId": "milf", "variation": "default" },
|
||||
{ "songId": "milf", "variation": "erect" },
|
||||
{ "songId": "milf", "variation": "pico" },
|
||||
|
||||
{ "songId": "cocoa", "variation": "default" },
|
||||
{ "songId": "cocoa", "variation": "erect" },
|
||||
{ "songId": "cocoa", "variation": "pico" },
|
||||
|
||||
{ "songId": "eggnog", "variation": "default" },
|
||||
{ "songId": "eggnog", "variation": "erect" },
|
||||
{ "songId": "eggnog", "variation": "pico" },
|
||||
|
||||
{ "songId": "winter-horrorland", "variation": "default" },
|
||||
{ "songId": "winter-horrorland", "variation": "erect" },
|
||||
{ "songId": "winter-horrorland", "variation": "pico" },
|
||||
|
||||
{ "songId": "senpai", "variation": "default" },
|
||||
{ "songId": "senpai", "variation": "erect" },
|
||||
{ "songId": "senpai", "variation": "pico" },
|
||||
|
||||
{ "songId": "roses", "variation": "default" },
|
||||
{ "songId": "roses", "variation": "erect" },
|
||||
{ "songId": "roses", "variation": "pico" },
|
||||
|
||||
{ "songId": "thorns", "variation": "default" },
|
||||
{ "songId": "thorns", "variation": "erect" },
|
||||
{ "songId": "thorns", "variation": "pico" },
|
||||
|
||||
{ "songId": "ugh", "variation": "default" },
|
||||
{ "songId": "ugh", "variation": "erect" },
|
||||
{ "songId": "ugh", "variation": "pico" },
|
||||
|
||||
{ "songId": "guns", "variation": "default" },
|
||||
{ "songId": "guns", "variation": "erect" },
|
||||
{ "songId": "guns", "variation": "pico" },
|
||||
|
||||
{ "songId": "stress", "variation": "default" },
|
||||
{ "songId": "stress", "variation": "erect" },
|
||||
{ "songId": "stress", "variation": "pico" },
|
||||
|
||||
{ "songId": "darnell", "variation": "default" },
|
||||
{ "songId": "darnell", "variation": "erect" },
|
||||
{ "songId": "darnell", "variation": "bf" },
|
||||
|
||||
{ "songId": "lit-up", "variation": "default" },
|
||||
{ "songId": "lit-up", "variation": "erect" },
|
||||
{ "songId": "lit-up", "variation": "bf" },
|
||||
|
||||
{ "songId": "2hot", "variation": "default" },
|
||||
{ "songId": "2hot", "variation": "erect" },
|
||||
{ "songId": "2hot", "variation": "bf" },
|
||||
|
||||
{ "songId": "blazin", "variation": "default" },
|
||||
{ "songId": "blazin", "variation": "erect" },
|
||||
{ "songId": "blazin", "variation": "bf" },
|
||||
]
|
||||
|
||||
LEVEL_IDS = [
|
||||
"tutorial",
|
||||
"week1",
|
||||
"week2",
|
||||
"week3",
|
||||
"week4",
|
||||
"week5",
|
||||
"week6",
|
||||
"week7",
|
||||
"weekend1",
|
||||
"week8",
|
||||
]
|
||||
|
||||
RANKS = [
|
||||
"PERFECT_GOLD",
|
||||
"PERFECT",
|
||||
"EXCELLENT",
|
||||
"GREAT",
|
||||
"GOOD",
|
||||
"SHIT",
|
||||
]
|
||||
|
||||
|
||||
def formatEventSong(event):
|
||||
result = []
|
||||
for song in SONG_IDS:
|
||||
result.append(event.format(
|
||||
songId = song["songId"],
|
||||
variation = song["variation"]
|
||||
))
|
||||
return result
|
||||
|
||||
def formatEventLevel(event):
|
||||
result = []
|
||||
for level in LEVEL_IDS:
|
||||
result.append(event.format(
|
||||
levelId = level
|
||||
))
|
||||
return result
|
||||
|
||||
def formatEventRank(event):
|
||||
result = []
|
||||
for rank in RANKS:
|
||||
result.append(event.format(
|
||||
rankName = rank
|
||||
))
|
||||
return result
|
||||
|
||||
def formatEvent(event):
|
||||
if "{songId}" in event or "{variation}" in event:
|
||||
return formatEventSong(event)
|
||||
|
||||
if "{levelId}" in event:
|
||||
return formatEventLevel(event)
|
||||
|
||||
if "{rankName}" in event:
|
||||
return formatEventRank(event)
|
||||
|
||||
return [event]
|
||||
|
||||
def createEvent(event):
|
||||
print(TEMPLATE.format(event=event))
|
||||
|
||||
def main():
|
||||
event_list = []
|
||||
|
||||
for event in EVENT_TEMPLATES:
|
||||
event_list.extend(formatEvent(event))
|
||||
|
||||
# Filter out duplicates then sort alphabetically
|
||||
event_list = list(set(event_list))
|
||||
event_list.sort()
|
||||
|
||||
for event in event_list:
|
||||
createEvent(event)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
|
||||
#function sleep(ms) {
|
||||
# console.log("sleeping for " + ms + "ms");
|
||||
# return new Promise(resolve => setTimeout(resolve, ms));
|
||||
#}
|
||||
#async function example() {
|
||||
# jQuery("#new-event-name").val("blueballs_blazin-erect"); jQuery("#save-new-event").click();
|
||||
# await sleep(1000);
|
||||
# jQuery("#new-event-name").val("blueballs_blazin-erect"); jQuery("#save-new-event").click();
|
||||
# await sleep(1000);
|
||||
#}
|
||||
#example();
|
||||
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build html5 -final
|
||||
echo UPLOADING TO ITCH
|
||||
butler push ./export/release/html5/bin ninja-muffin24/funkin-secret:html5
|
||||
butler status ninja-muffin24/funkin-secret:html5
|
||||
echo ITCH SHIT UPDATED LMAOOOOO
|
||||
pause
|
||||
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build html5 -debug
|
||||
echo UPLOADING TO ITCH
|
||||
butler push ./export/debug/html5/bin ninja-muffin24/funkin-secret:html5
|
||||
butler status ninja-muffin24/funkin-secret:html5
|
||||
echo ITCH SHIT UPDATED LMAOOOOO
|
||||
pause
|
||||
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build windows -final -clean
|
||||
echo UPLOADING 64 BIT VERSION TO ITCH
|
||||
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-64bit
|
||||
lime build windows -final -32
|
||||
echo UPLOADING 32 BIT VERSION TO ITCH
|
||||
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-32bit
|
||||
butler status ninja-muffin24/funkin:windows-32bit
|
||||
butler status ninja-muffin24/funkin:windows-64bit
|
||||
echo ITCH SHIT UPDATED LMAOOOOO
|
||||
pause
|
||||
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build windows -debug
|
||||
echo UPLOADING 64 BIT VERSION TO ITCH
|
||||
butler push ./export/debug/windows/bin ninja-muffin24/funkin:windows-secretBeta
|
||||
butler status ninja-muffin24/funkin:windows-secretBeta
|
||||
echo ITCH SHIT UPDATED LMAOOOOO
|
||||
pause
|
||||
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build windows -release
|
||||
echo UPLOADING 64 BIT VERSION TO ITCH
|
||||
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-64bit
|
||||
lime build windows -release -32
|
||||
echo UPLOADING 32 BIT VERSION TO ITCH
|
||||
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-32bit
|
||||
butler status ninja-muffin24/funkin:windows-32bit
|
||||
butler status ninja-muffin24/funkin:windows-64bit
|
||||
echo ITCH SHIT UPDATED LMAOOOOO
|
||||
pause
|
||||
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
color 0a
|
||||
cd ..
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build html5 -final -Dng
|
||||
echo ZIPPING
|
||||
cd export
|
||||
7z a -tzip -r swag release\html5\bin
|
||||
start .
|
||||
start https://www.newgrounds.com/projects/games/1528775
|
||||
pause
|
||||
@@ -0,0 +1,27 @@
|
||||
@echo off
|
||||
cd ..
|
||||
@echo on
|
||||
echo REBUILDING LIME FOR EXPORT (VERBOSE)
|
||||
@echo off
|
||||
color 0b
|
||||
@echo on
|
||||
lime rebuild windows -clean -v
|
||||
@echo off
|
||||
color 0a
|
||||
@echo on
|
||||
lime rebuild switch -clean -v
|
||||
@echo off
|
||||
color 0e
|
||||
@echo on
|
||||
lime rebuild tools -clean -v
|
||||
echo HOPE AND PRAY...
|
||||
@echo off
|
||||
color 0a
|
||||
@echo on
|
||||
echo BUILDING GAME
|
||||
lime build switch -final -clean -v
|
||||
@echo off
|
||||
color 0b
|
||||
@echo on
|
||||
echo NSP FILE CREATED
|
||||
pause
|
||||
@@ -0,0 +1,110 @@
|
||||
// Highlight keyframes in flash
|
||||
// drag .jsfl script in
|
||||
// will export the layer info of the first(?) element it finds?
|
||||
// maybe someone can extend this to add more depth / functionality!
|
||||
// see FramesJSFLParser.hx and CharSelectGF.hx for sample implementation
|
||||
|
||||
function splitArrayIntoChunks(array, chunkSize) {
|
||||
var result = [];
|
||||
for (var i = 0; i < array.length; i += chunkSize) {
|
||||
var chunk = array.slice(i, i + chunkSize);
|
||||
result.push(chunk);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var isJson = false;
|
||||
|
||||
function addField(name, variable, end)
|
||||
{
|
||||
return (isJson) ? addFJson(name, variable, end) : addF(variable, end);
|
||||
}
|
||||
function addFJson(name, variable, end) {
|
||||
return "\"" + name + "\": " + variable + ((!end) ? "," : "");
|
||||
}
|
||||
function addF(variable, end) {
|
||||
return variable + ((end)? "" : " ");
|
||||
}
|
||||
|
||||
|
||||
fl.outputPanel.clear();
|
||||
|
||||
var timeline = fl.getDocumentDOM().getTimeline();
|
||||
var daSelection = timeline.getSelectedFrames();
|
||||
var splitArrays = splitArrayIntoChunks(daSelection, 3);
|
||||
var uri = undefined;
|
||||
|
||||
|
||||
if (fl.version.substring(4).split(",")[0] < 13)
|
||||
{
|
||||
var macFormat = "Folder|TEXT[*.||";
|
||||
var winFormat = "Folder|*.||";
|
||||
var previewArea = {};
|
||||
uri = fl.browseForFileURL("save", "where to save files pick folder...", previewArea, macFormat, winFormat);
|
||||
}
|
||||
else
|
||||
uri = fl.browseForFileURL("save", "where to save files pick folder..", "Folder(*.)", "*.");
|
||||
|
||||
|
||||
for (var i = 0; i < splitArrays.length; i+=1)
|
||||
{
|
||||
var curLayerInfo = splitArrays[i];
|
||||
var curLayerInd = curLayerInfo[0];
|
||||
var curLayer = fl.getDocumentDOM().getTimeline().layers[curLayerInd];
|
||||
|
||||
var layerURI = uri;
|
||||
var fileName = "";
|
||||
var uris = uri.split("/");
|
||||
|
||||
fileName = uris[uris.length - 1];
|
||||
|
||||
|
||||
FLfile.createFolder(layerURI);
|
||||
|
||||
|
||||
var fileData = "{\n";
|
||||
if (!isJson)
|
||||
fileData = "";
|
||||
|
||||
var selectedFrames = curLayer.frames;
|
||||
var sliceLength = curLayerInfo[2] - curLayerInfo[1];
|
||||
selectedFrames =selectedFrames.slice(curLayerInfo[1],curLayerInfo[2]);
|
||||
|
||||
if (isJson)
|
||||
fileData += "\"frames\": [";
|
||||
|
||||
for (var frameInd = curLayerInfo[1]; frameInd < curLayerInfo[2]; frameInd+=1)
|
||||
{
|
||||
if (isJson)
|
||||
fileData += "\n{"
|
||||
var curFrame = curLayer.frames[frameInd];
|
||||
if (curFrame.isEmpty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var elementInd = 0; elementInd < curFrame.elements.length; elementInd+=1)
|
||||
{
|
||||
|
||||
var curElement = curFrame.elements[elementInd];
|
||||
|
||||
fileData += addField("x", curElement.left, false);
|
||||
fileData += addField("y", curElement.top, false);
|
||||
fileData += addField("alpha", (curElement.colorAlphaPercent == undefined) ? 100 : curElement.colorAlphaPercent, false);
|
||||
fileData += addField("scaleX", curElement.scaleX, false);
|
||||
fileData += addField("scaleY", curElement.scaleY, true);
|
||||
if (frameInd != curLayerInfo[2] - 1)
|
||||
fileData += "\n";
|
||||
}
|
||||
|
||||
if (isJson)
|
||||
fileData += "},";
|
||||
}
|
||||
if (isJson)
|
||||
fileData += "]";
|
||||
|
||||
if (isJson)
|
||||
fileData += "\n}";
|
||||
|
||||
FLfile.write(layerURI + "/" + fileName + ".txt", fileData);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# README
|
||||
|
||||
jsfl is a scripting format with javascript syntax, I believe it's old js (no `let`, idk the spec!)
|
||||
|
||||
Official Adobe JSFL docuementation
|
||||
[https://github.com/AdobeDocs/developers-animatesdk-docs/tree/master](https://github.com/AdobeDocs/developers-animatesdk-docs/tree/master)
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
|
||||
echo "Note! This should be run from the root of the main Funkin repo, after creating a universal macOS build!"
|
||||
echo "This script will assist in codesigning the Funkin.app for macOS"
|
||||
echo ""
|
||||
|
||||
TEAM_ID="Z7G7AVNGSH"
|
||||
ISSUER_ID="5205caca-2a9b-4b5e-9390-1db124cf51f4"
|
||||
DEVELOPER_CERT_NAME="Developer ID Application: The Funkin' Crew Incorporated ($TEAM_ID)"
|
||||
APP_PATH="export/release/macosUniversal/Funkin.app"
|
||||
|
||||
# Check if app exists
|
||||
if [ ! -d "$APP_PATH" ]; then
|
||||
echo "Error: $APP_PATH does not exist! Please build the app first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Preparing/Checking the AuthKey"
|
||||
team_key_path=~/.appstoreconnect/private_keys/
|
||||
# Check if directory exists, if not, create it
|
||||
if [ ! -d "$team_key_path" ]; then
|
||||
echo "The directory $team_key_path does not exist! Creating it now."
|
||||
mkdir -p "$team_key_path"
|
||||
echo ""
|
||||
echo "$team_key_path created, put the private key file in there (should be called 'AuthKey_XXXXXXX.p8')"
|
||||
echo "Ask Cameron for the private key file!"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# wait for the user to put the file in the directory, if it's not there
|
||||
while [ ! -f "${team_key_path}"AuthKey_*.p8 ]; do
|
||||
echo "Waiting for the private key file to be placed in $team_key_path... (press Ctrl+C to exit)"
|
||||
sleep 5
|
||||
done
|
||||
|
||||
key_id=$(ls "$team_key_path" | grep -oE '[A-Z0-9]{10}' | head -n 1)
|
||||
if [ -z "$key_id" ]; then
|
||||
echo "Error: Could not extract key ID from the AuthKey file name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Found AuthKey with key id: $key_id"
|
||||
key_path="${team_key_path}AuthKey_${key_id}.p8"
|
||||
|
||||
cd export/release/macosUniversal || { echo "Failed to change directory"; exit 1; }
|
||||
|
||||
echo "Ensuring properly formatted Entitlements.plist"
|
||||
if [ ! -f "Funkin.app/Contents/Entitlements.plist" ]; then
|
||||
echo "Error: Entitlements.plist not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
plutil -convert xml1 Funkin.app/Contents/Entitlements.plist
|
||||
plutil -convert xml1 Funkin.app/Contents/Info.plist
|
||||
plutil -lint Funkin.app/Contents/Entitlements.plist
|
||||
plutil -lint Funkin.app/Contents/Info.plist
|
||||
echo "Entitlements.plist and Info.plist should be properly formatted..."
|
||||
echo "Codesigning - Funkin.app"
|
||||
# Check the keychain for the funkin crew certificate
|
||||
echo "Checking for The Funkin' Crew certificate in the keychain..."
|
||||
if ! security find-identity -p codesigning | grep -q "The Funkin' Crew Incorporated"; then
|
||||
echo "The Funkin' Crew Developer ID Application certificate was not found in the keychain!"
|
||||
echo "Download the certificate from:"
|
||||
echo "https://developer.apple.com/account/resources/certificates/download/Z62SXF29U7"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Codesigning - Funkin.app"
|
||||
codesign --force --deep --timestamp --sign "$DEVELOPER_CERT_NAME" --options runtime Funkin.app || {
|
||||
echo "Code signing failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Codesigning - Funkin.app done!"
|
||||
# Debug info to see if the app is properly signed
|
||||
codesign -vv --deep --strict Funkin.app || {
|
||||
echo "Code signing verification failed"
|
||||
exit 1
|
||||
}
|
||||
echo ""
|
||||
echo "Zipping Funkin.app for notarization (using ditto)..."
|
||||
# Check if Funkin.app.zip already exists, if so, delete it
|
||||
if [ -f Funkin.app.zip ]; then
|
||||
echo "Funkin.app.zip already exists, deleting it..."
|
||||
rm -rf Funkin.app.zip
|
||||
fi
|
||||
|
||||
ditto -c -k --keepParent Funkin.app Funkin.app.zip || {
|
||||
echo "Failed to create zip file"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Funkin.app zipped, now sending to Apple for notarization..."
|
||||
xcrun notarytool submit Funkin.app.zip --issuer "$ISSUER_ID" --key-id "$key_id" --key "$key_path" --wait || {
|
||||
echo "Notarization submission failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Clean up zip file
|
||||
rm -rf Funkin.app.zip
|
||||
|
||||
echo "Stapling Funkin.app"
|
||||
xcrun stapler staple Funkin.app || {
|
||||
echo "Stapling failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Code sign information!"
|
||||
codesign -dv --verbose=4 Funkin.app
|
||||
|
||||
echo "Notarization information (stapler):"
|
||||
xcrun stapler validate Funkin.app || {
|
||||
echo "Stapler validation failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd ../../.. || { echo "Failed to return to original directory"; exit 1; }
|
||||
echo "Notarization complete! Funkin.app is now codesigned and notarized!"
|
||||
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
lime build mac -64 -release
|
||||
cd export/release
|
||||
rm -rf macosUniversal
|
||||
mkdir macosUniversal
|
||||
cp -r macos/bin/Funkin.app macosUniversal
|
||||
cd ../..
|
||||
lime build mac -arm64 -release
|
||||
cd export/release
|
||||
cp -r macos/bin/Funkin.app/Contents/MacOS/Funkin macosUniversal/Funkin.app/Contents/MacOS/FunkinArm
|
||||
cp -r macos/bin/Funkin.app/Contents/MacOS/lime.ndll macosUniversal/Funkin.app/Contents/MacOS/limeArm.ndll
|
||||
cd macosUniversal/Funkin.app/Contents/MacOS
|
||||
mv Funkin Funkin64
|
||||
mv lime.ndll lime64.ndll
|
||||
lipo -create -output lime.ndll lime64.ndll limeArm.ndll
|
||||
lipo -create -output Funkin Funkin64 FunkinArm
|
||||
rm FunkinArm Funkin64 lime64.ndll limeArm.ndll
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find all files in PNG format and execute oxipng to optimize file sizes
|
||||
cd ../assets/ && oxipng -o 6 --strip safe --alpha {} **/*.png
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Resize each health icon to 512x512
|
||||
find "./discord/" -name "icon-*.png" -exec sh -c 'ffmpeg -i {} -vf scale=512:512 "${0%.*}2.png"' {} \;
|
||||
Reference in New Issue
Block a user