Ejemplo n.º 1
0
static bool CreateDemoFileSplit(udtVMLinearAllocator& tempAllocator, udtContext& context, udtStream& file, const char* filePath, const char* outputFolderPath, u32 index, u32 startOffset, u32 endOffset)
{
	if(endOffset <= startOffset)
	{
		return false;
	}

	if(file.Seek((s32)startOffset, udtSeekOrigin::Start) != 0)
	{
		return false;
	}

	const udtProtocol::Id protocol = udtGetProtocolByFilePath(filePath);
	if(protocol == udtProtocol::Invalid)
	{
		return false;
	}

	udtVMScopedStackAllocator scopedTempAllocator(tempAllocator);

	const udtString filePathString = udtString::NewConstRef(filePath);

	udtString fileName;
	if(!udtPath::GetFileNameWithoutExtension(fileName, tempAllocator, filePathString))
	{
		fileName = udtString::NewConstRef("NEW_UDT_SPLIT_DEMO");
	}
	
	udtString outputFilePathStart;
	if(outputFolderPath == NULL)
	{
		udtString inputFolderPath;
		udtPath::GetFolderPath(inputFolderPath, tempAllocator, filePathString);
		udtPath::Combine(outputFilePathStart, tempAllocator, inputFolderPath, fileName);
	}
	else
	{
		udtPath::Combine(outputFilePathStart, tempAllocator, udtString::NewConstRef(outputFolderPath), fileName);
	}

	char* newFilePath = AllocateSpaceForString(tempAllocator, UDT_MAX_PATH_LENGTH);
	sprintf(newFilePath, "%s_SPLIT_%u%s", outputFilePathStart.String, index + 1, udtGetFileExtensionByProtocol(protocol));

	context.LogInfo("Writing demo %s...", newFilePath);

	udtFileStream outputFile;
	if(!outputFile.Open(newFilePath, udtFileOpenMode::Write))
	{
		context.LogError("Could not open file");
		return false;
	}

	const bool success = CopyFileRange(file, outputFile, tempAllocator, startOffset, endOffset);
	if(!success)
	{
		context.LogError("File copy failed");
	}

	return success;
}
Ejemplo n.º 2
0
UDT_API(s32) udtSplitDemoFile(udtParserContext* context, const udtParseArg* info, const char* demoFilePath)
{
	if(context == NULL || info == NULL || demoFilePath == NULL ||
	   !HasValidOutputOption(*info))
	{
		return (s32)udtErrorCode::InvalidArgument;
	}

	const udtProtocol::Id protocol = udtGetProtocolByFilePath(demoFilePath);
	if(protocol == udtProtocol::Invalid)
	{
		return (s32)udtErrorCode::InvalidArgument;
	}

	context->ResetForNextDemo(false);

	if(!context->Context.SetCallbacks(info->MessageCb, info->ProgressCb, info->ProgressContext))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	udtFileStream file;
	if(!file.Open(demoFilePath, udtFileOpenMode::Read))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	if(!context->Parser.Init(&context->Context, protocol, protocol))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	context->Parser.SetFilePath(demoFilePath);

	// TODO: Move this to api_helpers.cpp and implement it the same way Cut by Pattern is?
	udtParserPlugInSplitter plugIn;
	plugIn.Init(1, context->PlugInTempAllocator);
	context->Parser.AddPlugIn(&plugIn);
	if(!RunParser(context->Parser, file, info->CancelOperation))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	if(plugIn.GamestateFileOffsets.GetSize() <= 1)
	{
		return (s32)udtErrorCode::None;
	}

	udtVMLinearAllocator& tempAllocator = context->Parser._tempAllocator;
	tempAllocator.Clear();
	if(!CreateDemoFileSplit(tempAllocator, context->Context, file, demoFilePath, info->OutputFolderPath, &plugIn.GamestateFileOffsets[0], plugIn.GamestateFileOffsets.GetSize()))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	return (s32)udtErrorCode::None;
}
Ejemplo n.º 3
0
int udt_main(int argc, char** argv)
{
	if(argc == 1)
	{
		PrintHelp();
		return 0;
	}

	bool fileMode = false;
	const char* const inputPath = argv[argc - 1];
	if(udtFileStream::Exists(inputPath) && udtPath::HasValidDemoFileExtension(inputPath))
	{
		fileMode = true;
	}
	else if(!IsValidDirectory(inputPath))
	{
		fprintf(stderr, "Invalid file/folder path.\n");
		return 1;
	}

	bool recursive = false;
	Config config;
	for(int i = 1; i < argc - 1; ++i)
	{
		s32 localMaxThreads = 1;
		s32 localProtocol = (s32)udtProtocol::Invalid;
		const udtString arg = udtString::NewConstRef(argv[i]);
		if(udtString::StartsWith(arg, "-p=") &&
		   arg.GetLength() >= 4 &&
		   StringParseInt(localProtocol, arg.GetPtr() + 3))
		{
			if(localProtocol == 68)
			{
				config.OutputProtocol = udtProtocol::Dm68;
			}
			else if(localProtocol == 91)
			{
				config.OutputProtocol = udtProtocol::Dm91;
			}
		}
		else if(udtString::Equals(arg, "-r"))
		{
			recursive = true;
		}
		else if(udtString::StartsWith(arg, "-o=") &&
				arg.GetLength() >= 4 &&
				IsValidDirectory(argv[i] + 3))
		{
			config.CustomOutputFolder = argv[i] + 3;
		}
		else if(udtString::StartsWith(arg, "-t=") &&
				arg.GetLength() >= 4 &&
				StringParseInt(localMaxThreads, arg.GetPtr() + 3) &&
				localMaxThreads >= 1 &&
				localMaxThreads <= 16)
		{
			config.MaxThreadCount = (u32)localMaxThreads;
		}
	}

	if(config.OutputProtocol == udtProtocol::Invalid)
	{
		fprintf(stderr, "Invalid or unspecified output protocol number.\n");
		return 1;
	}

	if(fileMode)
	{
		if(!IsValidConversion((udtProtocol::Id)udtGetProtocolByFilePath(inputPath), config.OutputProtocol))
		{
			fprintf(stderr, "Unsupported conversion.\n");
			return 1;
		}

		udtFileInfo fileInfo;
		fileInfo.Name = udtString::NewNull();
		fileInfo.Path = udtString::NewConstRef(inputPath);
		fileInfo.Size = 0;

		return ConvertMultipleDemos(&fileInfo, 1, config) ? 0 : 1;
	}

	udtFileListQuery query;
	query.InitAllocators(64);
	query.FileFilter = &KeepOnlyCompatibleDemoFiles;
	query.FolderPath = udtString::NewConstRef(inputPath);
	query.Recursive = recursive;
	query.UserData = &config;
	GetDirectoryFileList(query);
	if(query.Files.IsEmpty())
	{
		fprintf(stderr, "No compatible demo file found.\n");
		return 1;
	}

	return ConvertMultipleDemos(query.Files.GetStartAddress(), query.Files.GetSize(), config) ? 0 : 1;
}
Ejemplo n.º 4
0
static bool KeepOnlyCompatibleDemoFiles(const char* name, u64 /*size*/, void* userData)
{
	const Config& config = *(const Config*)userData;

	return IsValidConversion((udtProtocol::Id)udtGetProtocolByFilePath(name), config.OutputProtocol);
}
Ejemplo n.º 5
0
	bool ProcessDemoFile(const char* filePath)
	{
		for(u32 i = 0; i < ID_MAX_CLIENTS; ++i)
		{
			_players[i].Name.clear();
			_players[i].Valid = false;
		}

		FileReader reader;
		if(!reader.Open(filePath))
		{
			return false;
		}

		udtCuContext* const cuContext = _cuContext;
		const u32 protocol = udtGetProtocolByFilePath(filePath);
		const s32 firstPlayerIdx = udtGetIdConfigStringIndex((u32)udtConfigStringIndex::FirstPlayer, protocol);
		if(firstPlayerIdx < 0)
		{
			PrintError("Failed to get the first index of player config strings");
			return false;
		}

		_protocol = (udtProtocol::Id)protocol;
		_protocolFirstPlayerCsIdx = firstPlayerIdx;

		s32 errorCode = udtCuStartParsing(cuContext, protocol);
		if(errorCode != udtErrorCode::None)
		{
			PrintError("udtCuStartParsing failed: %s", udtGetErrorCodeString(errorCode));
			return false;
		}

		udtCuMessageInput input;
		udtCuMessageOutput output;
		u32 continueParsing = 0;
		for(;;)
		{
			if(!reader.Read(&input.MessageSequence, 4))
			{
				PrintWarning("Demo is truncated");
				return true;
			}

			if(!reader.Read(&input.BufferByteCount, 4))
			{
				PrintWarning("Demo is truncated");
				return true;
			}

			if(input.MessageSequence == -1 &&
			   input.BufferByteCount == u32(-1))
			{
				// End of demo file.
				break;
			}

			if(input.BufferByteCount > ID_MAX_MSG_LENGTH)
			{
				PrintError("Corrupt input: the buffer length exceeds the maximum allowed");
				return false;
			}

			if(!reader.Read(_inMsgData, input.BufferByteCount))
			{
				PrintWarning("Demo is truncated");
				return true;
			}
			input.Buffer = _inMsgData;

			errorCode = udtCuParseMessage(cuContext, &output, &continueParsing, &input);
			if(errorCode != udtErrorCode::None)
			{
				PrintError("udtCuParseMessage failed: %s", udtGetErrorCodeString(errorCode));
				return false;
			}

			if(continueParsing == 0)
			{
				break;
			}

			AnalyzeMessage(output);
		}

		return true;
	}
Ejemplo n.º 6
0
UDT_API(s32) udtCutDemoFileByTime(udtParserContext* context, const udtParseArg* info, const udtCutByTimeArg* cutInfo, const char* demoFilePath)
{
	if(context == NULL || info == NULL || demoFilePath == NULL || cutInfo == NULL || 
	   !IsValid(*cutInfo))
	{
		return (s32)udtErrorCode::InvalidArgument;
	}

	const udtProtocol::Id protocol = udtGetProtocolByFilePath(demoFilePath);
	if(protocol == udtProtocol::Invalid)
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	context->ResetForNextDemo(false);
	if(!context->Context.SetCallbacks(info->MessageCb, info->ProgressCb, info->ProgressContext))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	udtFileStream file;
	if(!file.Open(demoFilePath, udtFileOpenMode::Read))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	if(info->FileOffset > 0 && file.Seek((s32)info->FileOffset, udtSeekOrigin::Start) != 0)
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	if(!context->Parser.Init(&context->Context, protocol, protocol, info->GameStateIndex))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	CallbackCutDemoFileStreamCreationInfo streamInfo;
	streamInfo.OutputFolderPath = info->OutputFolderPath;

	context->Parser.SetFilePath(demoFilePath);

	for(u32 i = 0; i < cutInfo->CutCount; ++i)
	{
		const udtCut& cut = cutInfo->Cuts[i];
		if(cut.StartTimeMs < cut.EndTimeMs)
		{
			context->Parser.AddCut(
				info->GameStateIndex, cut.StartTimeMs, cut.EndTimeMs, 
				&CallbackCutDemoFileStreamCreation, NULL, &streamInfo);
		}
	}

	context->Context.LogInfo("Processing for a timed cut: %s", demoFilePath);

	if(!RunParser(context->Parser, file, info->CancelOperation))
	{
		return (s32)udtErrorCode::OperationFailed;
	}

	return (s32)udtErrorCode::None;
}