A modded EditSaber for making beat saber maps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

730 lines
16 KiB

"use strict";
const fs = require("fs");
var clients = [];
var net = require('net');
try{
var request = require('request');
}
catch(err){
console.log(err);
console.log('Go read the damn readme. Run "npm install" or install the request module in some other way.');
process.exit()
}
var https = require('https');
var config = {};
var diff;
var fileSize;
var diffIndex;
var charIndex;
var diffFound = false;
var charFound = false;
var changesMade = false;
var downloadURL = "";
console.log("\n\n\n");
// Loading up json files and such that you need
try{
config = require('./config.json');
}
catch(err){
}
process.argv.shift();
process.argv.shift();
var type = "";
while(process.argv.length > 0)
{
var input = process.argv.shift()
if (input.startsWith("--"))
{
type = input.replace('--','');
}
else
{
if (type == "")
{
console.log('you fucked up');
process.exit()
}
else
{
config[type] = input;
}
}
}
// Check and display relevant info
try{
if(config.folder !== "" && config.folder !== undefined){
console.log(' Song folder: ' + config.folder);
}
else{
console.log('\nError: Fill in folder field');
process.exit()
}
if(config.difficulty !== "" && config.characteristic !== undefined){
console.log(' Song characteristic: ' + config.characteristic);
}
else{
console.log(' Song characteristic: Standard');
}
if(config.difficulty !== "" && config.difficulty !== undefined){
console.log(' Song difficulty: ' + config.difficulty);
}
else{
console.log('\nError: Fill in difficulty field');
process.exit()
}
if(config.port !== "" && config.port !== undefined){
console.log(' Port: ' + config.port);
}
else{
console.log('\nError: Fill in port field');
process.exit()
}
if(config.password != "" && config.password !== undefined){
console.log(' Password: ' + config.password);
}
else{
config.password = "";
console.log(' Password: no password being used');
}
if(config.download !== "" && config.download !== undefined){
console.log(' Song download: ' + config.download);
downloadURL = config.download;
}
}
catch(err){
console.log('config file is not formatted correctly');
process.exit()
}
var data = fs.readFileSync('./Songs/' + config.folder + '/info.dat');
// Loading stuff
try{
var info = loadJSON('./Songs/' + config.folder + '/info.dat');
}
catch(err){
console.log('Could not find file: Songs/' + config.folder + '/info.dat');
process.exit()
}
if (!config.characteristic)
{
config.characteristic = "Standard";
}
for (var i = 0; i < info._difficultyBeatmapSets.length; i++)
{
if (info._difficultyBeatmapSets[i]._beatmapCharacteristicName == config.characteristic)
{
for(var j = 0; j < info._difficultyBeatmapSets[i]._difficultyBeatmaps.length; j++)
{
if (info._difficultyBeatmapSets[i]._difficultyBeatmaps[j]._difficulty == config.difficulty)
{
diff = loadJSON('./Songs/' + config.folder + '/' + info._difficultyBeatmapSets[i]._difficultyBeatmaps[j]._beatmapFilename);
try{
fileSize = fs.statSync('./Songs/' + config.folder + '/' + info._songFilename);
}catch(err)
{
//console.log('\nFailed to find '+info.difficultyLevels[i].audioPath+'. now using fileSize argument');
if(!config.hasOwnProperty('fileSize'))
{
//console.log('could not use fileSize argument, finding from download URL');
request({
url: downloadURL,
method: "HEAD"
}, function(err, response, body) {
var downloadResponse = response.headers;
if (downloadResponse.hasOwnProperty('content-length'))
{
fileSize = downloadResponse['content-length'];
}
else
{
console.log('Unable to get file size. Please specify fileSize in config.json or as an argument');
process.exit();
}
});
}
fileSize = config['content-length'];
}
diffIndex = j;
charIndex = i;
diffFound = true;
break;
}
}
}
}
if (diff === null)
{
console.log('No proper difficulty found.');
process.exit();
}
if (diffFound == false)
{
console.log('Difficulty/Characteristic not found');
process.exit();
}
setInterval(saveFile, 300000);//save every 5 minutes
// if(config.download === "")
// {
// config.download = 'none';
// }
var server = net.createServer(function(socket){
socket.name = "wait";
socket.send = false;
//add new client to the list
clients.push(socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
if(socket.name == "wait")
{
if (config.password !== "" && data.toString().includes(";|;"))
{
console.log("attempted connection: " + data.toString().split(";|;")[1] + "\nPassword: " +data.toString().split(";|;")[0]);
if (config.password == data.toString().split(";|;")[0])
{
for (var i = 0; i < clients.length; i++)
{
if (clients[i].name == data.toString().split(";|;")[1] || "wait" == data.toString().split(";|;")[1])
{
if (socket.address == clients[i].address)
{
console.log('duplicate from same client. Destroying old client.')
clients[i].destroy();
clients.splice(i, 1);
}
else
{
socket.write('dc:duplicate name');
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
}
}
socket.name = data.toString().split(";|;")[1];
// Send a nice welcome message and announce
socket.write(config.folder.split('/').pop()+"::"+diffIndex*100+ charIndex+";;;"); //0
socket.write(JSON.stringify(info)+";;;"); //1
socket.write(info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename+";;;"); //2
socket.write(JSON.stringify(diff)+";;;");//3
socket.write(info._songFilename+";;;"+fileSize+";;;");//4 & 5
socket.write(downloadURL +";;;" );//6
socket.send = true;
}
else
{
socket.write('dc:wrong password');
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
}
else if (config.password === "")
{
if(data.toString().includes(";|;"))
{
data = data.toString().split(";|;")[1];
}
console.log("attempted connection: " + data);
for (var i = 0; i < clients.length; i++)
{
if (clients[i].name == data || "wait" == data)
{
socket.write('dc:duplicate name');
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
}
socket.name = data.toString();
// Send a nice welcome message and announce
socket.write(config.folder.split('/').pop()+"::"+diffIndex*100+ charIndex+";;;"); //0
socket.write(JSON.stringify(info)+";;;"); //1
socket.write(info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename+";;;"); //2
socket.write(JSON.stringify(diff)+";;;");//3
socket.write(info._songFilename+";;;"+fileSize+";;;");//4 & 5
socket.write(downloadURL +";;;" );//6
socket.send = true;
}
else if (config.password !== "" && !data.toString().includes(";|;"))
{
socket.write('dc:password required');
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
else
{
socket.write('dc:uhhh something else');
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
console.log(socket.name + " joined the session.");
broadcast("System:,:sy:,:"+ socket.name + " joined the session.;:;");
}
else
{
broadcast(data.toString(), socket);
var commands = data.toString().split(";:;");
for (var i = 0; i < commands.length; i++)
{
readMessage(commands[i]);
}
}
});
// Remove the client from the list when it leaves
socket.on('end', function () {
try
{
clients.splice(clients.indexOf(socket), 1);
console.log(socket.name + " left the session.");
broadcast("System:,:sy:,:"+ socket.name + " left the session.;:;");
broadcast(socket.name + ":,:rc;:;");
}
catch(err)
{
console.log(err);
}
});
socket.on('error',function () {
try
{
clients.splice(clients.indexOf(socket), 1);
broadcast("System:,:sy:,:"+ socket.name + " left the session.;:;");
broadcast(socket.name + ":,:rc;:;");
}
catch(err)
{
console.log(err);
}
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender)
{
return;
}
if (client.send == false)
{
return;
}
client.write(message);
});
}
});
//Get IP address
console.log('\n\n\n');
if (downloadURL === undefined || downloadURL === "")
{
var req = request.post('https://catbox.moe/user/api.php', function (err, resp, body) {
if (err) {
console.log(err);
} else {
// var downloadInfo = JSON.parse(body)
downloadURL = body;
console.log('Download URL generated: ' + body);
https.get('https://ifconfig.co/ip', function(res){
res.setEncoding('utf8');
res.on('data', function(chunk){
server.listen(config.port, '0.0.0.0');
process.stdout.write("Server Started on IP address: ")
console.log(chunk);
});
res.on('error', function(err) {
server.listen(config.port, '0.0.0.0');
process.stdout.write("Server Started");
});
});
}
});
var form = req.form();
form.append('reqtype', 'fileupload');
form.append('fileToUpload', fs.createReadStream('./Songs/'+config.folder+'/'+info._songFilename));
}else
{
https.get('https://ifconfig.co/ip', function(res){
res.setEncoding('utf8');
res.on('data', function(chunk){
server.listen(config.port, '0.0.0.0');
process.stdout.write("Server Started on IP address: ")
console.log(chunk);
});
res.on('error', function(err) {
server.listen(config.port, '0.0.0.0');
process.stdout.write("Server Started");
});
});
}
function readMessage(message)
{
changesMade = true;
var type = message.split(":,:")[1];
switch(type)
{
case 'an':
try{
addNote(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 'rn':
try{
removeNote(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 'ae':
try{
addEvent(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 're':
try{
removeEvent(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 'aw':
try{
addWall(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 'rw':
try{
removeWall(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
case 'ab':
try{
addBookmark(message.split(':,:')[2].split("|||"));
}
catch(err){
}
break;
case 'rb':
try{
removeBookmark(message.split(':,:')[2].split(" "));
}
catch(err){
}
break;
default:
//console.log(message);
break;
}
}
function addNote(data)
{
var note = stringToNote(data)
if (!hasNull(note))
{
diff._notes.push(note);
}
}
function removeNote(data)
{
for (var j = diff._notes.length -1 ; j >= 0; j--)
{
if (sameNote(diff._notes[j],stringToNote(data)))
{
diff._notes.splice(j,1);
break;
}
}
}
function stringToNote(data)
{
return {_time: parseFloat(data[0]),
_lineIndex: parseInt(data[1]),
_lineLayer: parseInt(data[2]),
_type: parseInt(data[3]),
_cutDirection: parseInt(data[4])};
}
function sameNote(note1,note2)
{
if (Math.abs(note1._time - note2._time) > 0.001)
return false;
if (note1._lineIndex != note2._lineIndex)
return false;
if (note1._lineLayer != note2._lineLayer)
return false;
if (note1._type != note2._type)
return false;
if (note1._cutDirection != note2._cutDirection)
return false;
return true;
}
function addEvent(data)
{
if (data.length == 3)
{
var event = stringToEvent(data)
if (!hasNull(event))
{
diff._events.push(event);
}
}
else
{
var event = stringToEvent(data)
if (!hasNull(event))
{
diff._BPMChanges.push(stringToBPM(data));
}
}
}
function removeEvent(data)
{
if (data.length == 3)
{
for (var j = diff._events.length -1 ; j >= 0; j--)
{
if (sameEvent(diff._events[j],stringToEvent(data)))
{
diff._events.splice(j,1);
break;
}
}
}
else
{
for (var j = diff._BPMChanges.length -1 ; j >= 0; j--)
{
if (sameBPM(stringToBPM(data), diff._BPMChanges[j]))
{
diff._BPMChanges.splice(j,1);
}
}
}
}
function sameEvent(event1,event2)
{
if (Math.abs(event1._time - event2._time) > 0.001)
return false;
if (event1._type != event2._type)
return false;
if (event1._value != event2._value)
return false;
return true;
}
function sameBPM(event1,event2)
{
if (Math.abs(event1._BPM - event2._BPM) > 0.02)
return false;
if (Math.abs(event1._time - event2._time) > 0.001)
return false;
return true;
}
function stringToEvent(data)
{
return {
_time: parseFloat(data[0]),
_type: parseInt(data[1]),
_value: parseInt(data[2])
};
}
function stringToBPM(data)
{
return {
_BPM:parseFloat(data[0]),
_time:parseFloat(data[1]),
_beatsPerBar:parseFloat(data[2]),
_metronomeOffset:parseFloat(data[3])}
}
function addWall(data)
{
var wall = stringToWall(data)
if (!hasNull(wall))
{
diff._obstacles.push(wall);
}
}
function removeWall(data)
{
for (var j = diff._obstacles.length -1 ; j >= 0; j--)
{
if (sameWall(diff._obstacles[j],stringToWall(data)))
{
diff._obstacles.splice(j,1);
break;
}
}
}
function stringToWall(data)
{
return {_time: parseFloat(data[0]),
_lineIndex: parseInt(data[1]),
_type: parseInt(data[2]),
_duration: parseFloat(data[3]),
_width: parseInt(data[4])
};
}
function sameWall(wall1,wall2)
{
if (Math.abs(wall1._time - wall2._time) > 0.001)
return false;
if (wall1._lineIndex != wall2._lineIndex)
return false;
if (wall1._type != wall2._type)
return false;
if (Math.abs(wall1._duration - wall2._duration) > 0.001)
return false;
if (wall1._width != wall2._width)
return false;
return true;
}
function addBookmark(data)
{
diff._bookmarks.push(stringToBookmark(data));
}
function removeBookmark(data)
{
for (var j = diff._bookmarks.length - 1; j >= 0; j--)
{
if (Math.abs(diff._bookmarks[j]._time - stringToBookmark(data)._time) < 0.001)
{
diff._bookmarks.splice(j,1);
break;
}
}
}
function stringToBookmark(data)
{
return {
_time: parseFloat(data[0]),
_name: data[1]
};
}
function saveFile()
{
if (changesMade)
{
fs.writeFile('./Songs/' + config.folder + '/' + info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename, JSON.stringify(diff), function(err) {
if (err)
console.log(err);
else
{
console.log ("file successfully saved.\nNote Count: "+ diff._notes.length+"\nEvent Count: "+diff._events.length);
}
});
}
changesMade = false;
}
// server.getConnections(function(err,count){
// console.log(count);
// });
function disconnectSoon(socket)
{
if(socket.name == "wait" || socket.name.length > 30)
{
clients.splice(clients.indexOf(socket), 1);
socket.destroy();
return;
}
}
function hasNull(object)
{
for(var key in object) {
if (object[key] === null)
{
try
{
console.log("null object detected at :" + object._time);
}
catch(err)
{
console.log("null object detected")
}
return true;
}
}
}
function loadJSON(file) {
var data = fs.readFileSync(file);
return JSON.parse(data);
}