If you want to help us maintaining this wiki, check out our discord server: https://discord.gg/3u69jMa 

Difference between revisions of "Republic Commando UCC"

From SWRC Wiki
Jump to navigation Jump to search
 
(34 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Author: Leon
UCC is a command line utility for early Unreal engine games. Star Wars: Republic Commando ships without one, but a custom one has been made available as a result of reverse engineering.


Used Tools: [[MS Visual Studio 2003]]
Description: A custom UCC.exe for Republic Commando. Used for executing Unreal Commandlets.


Description: A self written UCC for Republic Commando. Used for executing Unreal Commandlets.
Latest Build: [https://github.com/SWRC-Modding/CT/releases here]


Github: [https://github.com/Leon280698/Republic-Commando-UCC here]


Latest Build: [http://www.moddb.com/games/star-wars-republic-commando/downloads/star-wars-republic-commando-ucc-exe here]
[[File:Uccshow.PNG]]


===== Batchexport Commandlet =====


==UCC.cpp==
The batchexport commandlet is made available by UCC. This commandlet can parse the game's resource archives in order to export any exportable type in bulk. Here is the syntax for converting some texture package, called "exampletexturepackage.utx" from the game into a set of tga files in ExampleOutputFolder:


<source lang="cpp" line">
'''<sup>./ucc.exe batchexport exampletexturepackage.utx texture tga ".\\ExampleOutputFolder"</sup>'''
/*
* This code compiles to a dll. In order to use it, SWRepublicCommando.exe needs to be modified so
* that it calls this dll's 'uccInit' instead of 'appInit' from Core.dll
* Also it's subsystem should be changed from window to console
* Everything compiles fine with Visual Studio .NET 2003 for maximum compatibility since it was
* also used to compile Republic Commando
* The following settings are needed to compile everything without errors:
* - Character Set = Not Set
* - Struct Member Alignment = 4 Bytes
* - Calling Convention = __fastcall
*/


#pragma comment(lib, "Core.lib")
In particular, UCC can extract batches of sounds from the UAX archives where Republic Commando's voice lines and sound effects are stored. The batchexport commandlet does this. See [[Extract_Game_Audio_Using_UCC|how to extract game audio using UCC]] for details.
 
#include <windows.h> //VirtualProtect
 
#include <cstdio> //std::puts
#include <cstdlib> //__argc, __argv
#include <cctype> //std::toupper
#include <string>
 
#include "Core/inc/Core.h"
 
namespace{
//Global variables
 
FOutputDevice* GFileLog; //OutputDevice that writes to a log file
 
//All commandlets shipped with RC
const char* DefaultCommandlets[40][2] = {
{"Editor", "AnalyzeContent"},
{"Editor", "BatchExport"},
{"Editor", "ChecksumPackage"},
{"Editor", "CheckUnicode"},
{"Editor", "CompareInt"},
{"IpDrv", "Compress"},
{"Editor", "CompressToDXT"},
{"Editor", "Conform"},
{"Editor", "ConvertMaterial"},
{"Editor", "CutdownContent"},
{"Editor", "DataRip"},
{"IpDrv", "Decompress"},
{"XGame", "DumpGameList"},
{"Editor", "DumpInt"},
{"XGame", "DumpMapList"},
{"XGame", "DumpMutatorList"},
{"Editor", "DumpSoundParams"},
{"Editor", "DumpSoundPropLog"},
{"XGame", "DumpWeaponList"},
{"Editor", "DXTConvert"},
{"Editor", "Exec"},
{"Editor", "FontUpdate"},
{"Core", "HelloWorld"},
{"Editor", "ImportAse"},
{"Editor", "ImportTexture"},
{"Editor", "ListPackageContents"},
{"Editor", "Make"},
{"Editor", "MapConvert"},
{"Editor", "Master"},
{"Editor", "MergeInt"},
{"Editor", "ModifyPackageFlags"},
{"Editor", "PackageFlag"},
{"Editor", "Pkg"},
{"Editor", "RearrangeInt"},
{"Editor", "ResavePackage"},
{"Engine", "Server"},
{"Editor", "StripSource"},
{"Editor", "TestMath"},
{"Editor", "UpdateUMod"},
{"Editor", "XACTExport"}
};
 
//Helper function used for case-insensitive string comparisons
std::string ToUpper(const std::string& s){
std::string result;
 
result.reserve(s.size());
 
for(std::size_t i = 0; i < s.size(); i++)
result += std::toupper(s[i]);
 
return result;
}
 
/*
* Replacement for Serialize function of 'InWarn', passed to appInit
* Have to do this vtable hack because creating new FFeedbackContext and passing it results in crash
*/
void __stdcall FFeedbackContextAnsiSerialize(const TCHAR* V, EName Event){
TCHAR Temp[1024]= "";
 
if(Event==NAME_Title){
return;
}else if(Event==NAME_Heading){
appSprintf(Temp, "\n--------------------%s--------------------", V);
 
V = Temp;
}else if(Event==NAME_SubHeading){
appSprintf(Temp, "%s...", V);
 
V = Temp;
}else if(Event == NAME_Error || Event == NAME_Warning || Event == NAME_ExecWarning || Event == NAME_ScriptWarning || Event == NAME_Critical){
appSprintf(Temp, "%s: %s", *FName(Event), V);
 
V = Temp;
}
 
std::puts(V);
 
GFileLog->Serialize(V, Event);
}
}
 
//Entry point, called by modified SWRepublicCommando.exe
__declspec(dllexport) void uccInit(const TCHAR* InPackage, const TCHAR* InCmdLine, FOutputDevice* InLog, FOutputDeviceError* InError,
  FFeedbackContext* InWarn, FConfigCache*(*ConfigFactory)(), UBOOL RequireConfig){
int ExitVal = EXIT_SUCCESS;
GFileLog = InLog;
 
//Small vtable hack to have InWarn call my own Serialize function
//===============================================================
PVOID* vtable = *reinterpret_cast<PVOID**>(InWarn);
DWORD dwNull;
 
VirtualProtect(&vtable[0], 4, PAGE_EXECUTE_READWRITE, &dwNull);
 
vtable[0] = FFeedbackContextAnsiSerialize;
//===============================================================
 
InWarn->Log("=======================================");
InWarn->Log("ucc.exe for Star Wars Republic Commando");
InWarn->Log("made by Leon0628");
InWarn->Log("=======================================\n");
 
//Server stuff...
 
for(int i = 1; i < __argc; i++){
std::string Temp = ToUpper(__argv[i]);
 
//In case user wants to start a server, redirecting log to console and returning to SWRepublicCommando.exe
//Uses RC server command line syntax, not Engine.ServerCommandlet!!!
if(Temp == "-SERVER"){
appInit(InPackage, InCmdLine, InWarn, InError, InWarn, ConfigFactory, RequireConfig);
 
return;
}
}
 
//Actual UCC stuff...
 
try{
GIsStarted = 1;
GIsGuarded = 1;
 
appInit(InPackage, InCmdLine, InLog, InError, InWarn, ConfigFactory, 1);
UObject::SetLanguage("int");
 
if(__argc > 1){
//Initializing global state
GIsUCC = GIsClient = GIsServer = GIsEditor = GIsScriptable = GLazyLoad = 1;
 
std::string ClassName = __argv[1];
std::string Upper = ToUpper(ClassName);
DWORD LoadFlags = LOAD_NoWarn | LOAD_Quiet;
bool bIsUScript = true; //Whether the commandlet is written in UnrealScript or native code
 
//Looking it up in list of default commandlets
for(int i = 0; i < ARRAY_COUNT(DefaultCommandlets); i++){
if(Upper == ToUpper(DefaultCommandlets[i][1]) || //Only name without package
  Upper == ToUpper(DefaultCommandlets[i][1]) + "COMMANDLET"){ //Only name with "Commandlet"
ClassName = std::string(DefaultCommandlets[i][0]) + "." + DefaultCommandlets[i][1] + "Commandlet";
 
//HelloWorld is the only standard commandlet written in UnrealScript
bIsUScript = ClassName == "Core.HelloWorldCommandlet";
 
break;
}else if(Upper == ToUpper(std::string(DefaultCommandlets[i][0]) + "." + DefaultCommandlets[i][1]) || //Package.Name
Upper == ToUpper(std::string(DefaultCommandlets[i][0]) + "." + DefaultCommandlets[i][1]) + "COMMANDLET"){ //Package.Name + "Commandlet"
//HelloWorld is the only standard commandlet written in UnrealScript
bIsUScript = Upper == "CORE.HELLOWORLD" || Upper == "CORE.HELLOWORLDCOMMANDLET";
 
break;
}
}
 
if(ToUpper(ClassName) == "EDITOR.MAKE" || ToUpper(ClassName) == "EDITOR.MAKECOMMANDLET")
LoadFlags |= LOAD_DisallowFiles; //Not sure what this does but the original ucc has it aswell...
 
UClass* Class = UObject::StaticLoadClass(UCommandlet::StaticClass(), NULL, ClassName.c_str(), NULL, LoadFlags, NULL);
 
if(!Class) //If class failed to load, appending "Commandlet" and trying again
Class = UObject::StaticLoadClass(UCommandlet::StaticClass(), NULL, (ClassName + "Commandlet").c_str(), NULL, LoadFlags, NULL);
 
if(Class){
UCommandlet* Commandlet = ConstructObject<UCommandlet>(Class);
 
InWarn->Logf("Executing %s\n", Class->GetFullName());
 
Commandlet->InitExecution();
Commandlet->ParseParms(appCmdLine());
 
GLog = InWarn; //Redirecting commandlet output to console
 
if(!bIsUScript)
Commandlet->Main(appCmdLine());
else
Commandlet->Main(FString(appCmdLine())); //For non-native commandlets this overload has to be used
 
GLog = GFileLog;
}else{
InWarn->Logf("Commandlet %s not found", ClassName.c_str());
}
}else{
InWarn->Log("Usage:");
InWarn->Log("    ucc PackageName.CommandletName <parameters>");
InWarn->Log("OR");
InWarn->Log("    ucc uscript PackageName.CommandletName <parameters>");
InWarn->Log("    for commandlets written in UnrealScript");
}
 
appPreExit();
GIsGuarded = 0;
}catch(...){
ExitVal = EXIT_FAILURE;
GIsGuarded = 0;
InError->HandleError();
}
 
appExit();
std::exit(ExitVal); //Needed in order to prevent this function from returning to SWRepublicCommando.exe
}
</source>

Latest revision as of 20:05, 4 October 2023

UCC is a command line utility for early Unreal engine games. Star Wars: Republic Commando ships without one, but a custom one has been made available as a result of reverse engineering.

Description: A custom UCC.exe for Republic Commando. Used for executing Unreal Commandlets.

Latest Build: here


Uccshow.PNG

Batchexport Commandlet

The batchexport commandlet is made available by UCC. This commandlet can parse the game's resource archives in order to export any exportable type in bulk. Here is the syntax for converting some texture package, called "exampletexturepackage.utx" from the game into a set of tga files in ExampleOutputFolder:

./ucc.exe batchexport exampletexturepackage.utx texture tga ".\\ExampleOutputFolder"

In particular, UCC can extract batches of sounds from the UAX archives where Republic Commando's voice lines and sound effects are stored. The batchexport commandlet does this. See how to extract game audio using UCC for details.