CS Code convertion: Difference between revisions
No edit summary |
|||
(225 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
=== Types === | === Types === | ||
csArray<> -> TArray | |||
csBox2 -> TArray<FVector2D> | |||
If you need to have unique key-value pairs: | |||
csHash<Value> -> TMap<int,Value> | |||
csHash<Value,Key> -> TMap<Key,Value> (note the swap of Key and Value) | |||
If you need have multiple values for the same key: | |||
csHash<Value,Key> -> TMultiMap<Key,Value> (notice the swap of Key and Value) | |||
csHashCompute(string) -> StrUtils::hashCompute(string) | |||
csList -> TDoubleLinkedList | |||
csMD5::Digest -> to be bettere analyzed, for now just temporary | |||
csPDelArray<PhonicEntry> -> TArray<PhonicEntry*>; (note the pointer in UE) | |||
csRandomGen -> FMath::FRandRange(low, high); | |||
psGetRandom() -> FMath::FRandRange(0, 1); // CAREFUL: psGetRandom 0 <= num < 1 WHILE FRandRange 0 <= num <= 1 | |||
psserver->GetRandomRange(pos, range) -> (pos - range + FMath::FRandRange(0,1)*range*2) | |||
If you want to generate Integer random then use FMath::RandRange(1,10) // Returns a random number >= Min and <= Max | |||
psserver->rng->Get(100) -> FMath::FRandRange(0,100); | |||
csRef<iDocumentNode> containerNode -> FXmlNode *containerNode | |||
csRefArray<csString> -> TArray<FString*> | |||
csRegExpMatcher -> FRegexPattern , FRegexMatcher (check msgmanager.cpp:234) | |||
csSet -> TArray (but be careful about insertions as csSet.Add checks for uniqueness) | |||
csString -> psString or FString | csString -> psString or FString | ||
psStringArray | csStringSet -> StringSet ( #include "util/strset.h" ) | ||
csStringArray -> TArray<FString> | |||
psStringArray -> TArray<FString> | |||
csSquaredDist::PointPoint() -> FVector::Dist(v1,v2) | |||
csTicks -> float (time_t can be used only when 100% sure we can use an integer and no convertion issues from float) | |||
CS::Threading::AtomicOperations::Increment(&nextid); -> FThreadSafeCounter.Increment() | |||
CS::Threading::MutexScopedLock ScopeLock(mutex); -> FCriticalSection mutex; FScopeLock ScopeLock(mutex); | |||
csTuple2 -> TPair | |||
csVector2 -> FIntPoint | |||
csVector3 -> FVector | |||
?? csSet -> TArray ?? | |||
uint -> uint32 | uint -> uint32 | ||
uint32_t -> #include <stdint.h> | |||
iResultRow -> psResultRow | |||
StringIDValue -> int (is this a correct assumption?) | |||
WordArray -> TArray<FString> with space separator. Verify if this assumption is enough | |||
//WordArray words(trigger.GetString()); | |||
TArray<FString> words; | |||
trigger.ParseIntoArray(words, TEXT(" "), true); | |||
iVFS -> not used in UE, just delete the reference. | |||
CS::Utility::PriorityQueue<TaskEntry> -> TArray<TaskEntry> items; use items.Heapify() to order. | |||
NPC -> psNPCBrain | |||
=== Types conversion === | === Types conversion === | ||
FString to char* -> const char *myData = TCHAR_TO_ANSI(*NameString); | FString to char* -> const char *myData = TCHAR_TO_ANSI(*NameString); | ||
Line 33: | Line 96: | ||
char* to FString -> ANSI_TO_TCHAR(NameString); | char* to FString -> ANSI_TO_TCHAR(NameString); | ||
int to FString -> FString::FromInt(myInt); | |||
float to FString -> FString::SanitizeFloat(myFloat); | |||
int32 MyShinyNewInt = FCString::Atoi(*TheString); | |||
float MyShinyNewFloat = FCString::Atof(*TheString); | |||
=== Functions on csString === | |||
csString csv.AppendFmt(",%d,%d", fs->faction->id, fs->score); -> csv.Append(FString::Printf(TEXT(",%d,%d"), fs->faction->id, fs->score)); | |||
csString.AppendFmtV(fmt, args) -> vsprintf(line, fmt, args); script.Append(line); | |||
csString.Clear() -> Empty() | |||
csString. | csString input.Collapse() -> output = StrUtils::Collapse(input) | ||
csString.CompareNoCase() returns TRUE if equal -> FString.Compare("ADD", ESearchCase::IgnoreCase)==0 returns 0 if equal | |||
csString.DeleteAt(start) -> FString.RemoveAt(start) | |||
csString.DeleteAt(start,count) -> FString.RemoveAt(start,count) | csString.DeleteAt(start,count) -> FString.RemoveAt(start,count) | ||
csString.Downcase() -> FString. | csString str.Detach() -> TCHAR_TO_ANSI(*str) detaches the data from the csString | ||
csString.Downcase() -> mystring = mystring.ToLower() (NOTE the assignment in UE) | |||
csString.Find(search, pos, ignore_case) -> FString.Find(search, ESearchCase::IgnoreCase) | |||
csString.FindLast('-') -> int pos; csString.FindLastChar('-', pos) | |||
csString.FindLast('-', startposition) -> pos = csString.Find('-', pos) | |||
csString end = resp.Find("]", start); -> int end = resp.Find("]",ESearchCase::IgnoreCase , ESearchDir::FromStart, start); | |||
csString.Free() -> mystring = "" | |||
csString.FindFirst ('a') -> int pos; FString.FindChar(' ',pos); | |||
csString pos = script.FindFirst(';', start); -> pos = script.Find("]",ESearchCase::IgnoreCase , ESearchDir::FromStart, start); | |||
script.FindStr("string") -> script.Find("string"); | |||
mystr.FindReplace (search, replace) -> mystr = mystr.Replace(search, replace); (NOTE the assignment in UE) | |||
csString.FindSubString() -> FString.Find() | |||
string.Format("hey %s", param) -> string = FString::Printf(TEXT("hey %s"), param) (NOTE the assignment in UE) | |||
csString.GetAt(0) -> [0] | |||
csString.GetData() -> TCHAR_TO_ANSI(*mystring) | |||
csString.GetDataSafe() -> TCHAR_TO_ANSI(*mystring) | |||
csString.Insert(pos, str) -> FString.InsertAt(pos, string) | |||
csString.Length() -> Len() | csString.Length() -> Len() | ||
csString. | csString.LTrim() -> FString.Trim() | ||
csString.Replace(from, to) -> mystr = mystr.Replace(TEXT("fromtext"), *to); (NOTE the assignment in UE) | |||
csString.ReplaceSubString(search, replace) -> mystr = mystr.Replace(search, replace) (NOTE the assignment in UE) | |||
csString.ReplaceAll(search, replace) -> mystr = mystr.Replace(search, replace) (NOTE the assignment in UE) | |||
csString.Slice(5) -> FString.RightChop(5); if there is only one parameter CS assumes the second to be -1, so the end of the string | |||
csString.Slice(0,5) -> mystr = FString.Left(5); | |||
csString.Slice(a,b) -> mystr = FString.Mid(a,b); | |||
csString.Split(csStringArray& arr, char delim) -> FString.ParseIntoArray(arr,TEXT(".")); | |||
csString resp.SubString(saySegment,start,numchars); -> FString saySegment = resp.Mid(start, numchars); | |||
csString resp.SubString(saySegment,start); -> FString saySegment = resp.RightChop(start); | |||
csString response.StartsWith("<Examine>", true) -> response.StartsWith("<Examine>", ESearchCase::IgnoreCase) (true ignore case, false case sensitive) | |||
csString.RTrim() -> FString.TrimTrailing() | |||
csString xxx = mystring.Trim() -> FString.TrimStartAndEnd() (this one does NOT change the string in place) | |||
csString : mystring.Trim() -> FString.TrimStartAndEndInline() (this one changes the string in place) | |||
csString.Truncate(5) -> modifiedString = FString.Left(5) | |||
csString.Upcase() -> FString.ToUpper() | |||
const char *myData = str->GetData(); -> TArray<TCHAR> myData = str.GetCharArray(); | |||
psString.GetLine() scr.GetLine(start,line); -> line = StrUtils::GetLine(scr,start); | |||
=== Functions other types === | |||
psserver->GetRandom() provides a number between 0.0 and 1.0 -> FMath::FRandRange(0.0, 1.0) | |||
csRandomGen.Get() -> FMath::FRandRange(0.0, 1.0) | |||
psserver->GetRandom(limit) -> provides a number between 0.0 and limit -> FMath::FRandRange(0.0, limit) If provided with float it returns a float, if int then returns int. | |||
csPDelArray.GetSize() -> TArray.Num() | csPDelArray.GetSize() -> TArray.Num() | ||
csPDelArray.Push() -> TArray.Add() | |||
csArray.Delete(item) -> TArray.Remove(item) | |||
csArray.DeleteAll() -> TArray.Empty() | |||
csArray.DeleteIndex(i) -> TArray.RemoveAt(i) | |||
csArray.DeleteIndexFast(i) -> TArray.RemoveAt(i) | |||
csArray.Extract(index) -> item = TArray[index]; TArray.RemoveAt(index); | |||
csArray.FindStr("str", start) -> end = StrUtils::FindStr(words, "str", start); | |||
csArray.FormatPush("%d",i); -> TArray.Add(FString::Printf(TEXT("%d",i)); | |||
csArray.GetSize() -> TArray.Num(); | |||
csArray myarray.Merge(otherArray) -> TArray.Append(otherArray) | |||
csArray myarray.Get(0) -> TArray myarray[0] | |||
csArray.Insert(index, item) -> TArray.Insert(item, index); (note switch of order) | |||
csArray.InsertSorted(item) -> TArray.Add(item); TArray.Sort(); | |||
csArray.IsEmpty() -> TArray.Num()==0 | |||
csArray.PushSmart(item) -> int found = TArray.Find(item); if (found == INDEX_NONE) TArray.Add(item); | |||
csArray.Put(index, item) -> TArray.RemoveAt(index); TArray.Insert(item, index); (note switch of order) | |||
csArray.ShrinkBestFit() -> TArray.Shrink(); | |||
csArray.SplitString(str, ',') -> str.ParseIntoArray(array, TEXT(",")); | |||
csArrayItemNotFound -> INDEX_NONE | |||
csList.Delete(node) -> TDoubleLinkedList.RemoveNode(node) | |||
csList.DeleteAll() -> TDoubleLinkedList.Empty() | |||
csList.Front() -> TDoubleLinkedList.GetHead() | |||
csList.IsEmpty() -> TDoubleLinkedList.Num()==0 | |||
csList.PushBack() -> TDoubleLinkedList.AddTail() adds an element at the end of the list | |||
csList.PushFront() -> TDoubleLinkedList.AddHead() adds an element at the beginning of the list | |||
csList attackList.PopFront() -> attackList.RemoveNode(attackList.GetHead()); deletes an element at the beginning | |||
csList attackList.Pop() -> attackList.RemoveNode(attackList.GetTail()); deletes an element at the end of the list | |||
csList values.PopBack() -> values.RemoveNode(values.GetTail()); Deletes the last element of the list | |||
for(csList<psItem*>::Iterator newitemitr(newitem); newitemitr.HasNext();) -> | |||
TDoubleLinkedList<ApsItem*>::TIterator i(itemlist.GetHead()); | |||
while (i) { ....} | |||
csHash.Delete(id, item) -> If not using multimap then TMap.Remove(id); | |||
csHash.DeleteAll() -> TMap.Empty() | |||
csHash.DeleteAll(name) -> If used as TMap (meaning no duplicate keys -> TMap.Remove(name) | |||
csHash.Get(key,fallback) -> TMap.FindRef(key) | |||
csHash.GetAll(key) example: channelSubscribers.GetAll(key) -> | |||
TArray<uint32_t> subscribers; | |||
channelSubscribers.GetKeys(subscribers); | |||
for(size_t i = 0; i < subscribers.Num(); i++) | |||
{ | |||
// filter subscribers by given channelID | |||
if (subscribers[i] == channelID) { | |||
csHash.GetElementPointer(name) -> TMap.Find(name); | |||
csHash.GetSize() -> TMap.Num(); | |||
csHash.In() -> TMap.Contains() | |||
CS::IsNaN() -> isnan() | |||
csHash.Put(value, key) -> TMap.Add(value, key) (NOTE NO swap of parameters) | |||
csHash.PutUnique() -> TMap.Add() (we should test if this is ok) | |||
csHash<FactionStanding*, int>::GlobalIterator iter(factionstandings.GetIterator()); -> TMap<int, FactionStanding*>::TIterator iter = factionstandings.CreateIterator(); | |||
csHash if(iter.HasNext()) -> if(iter) | |||
csHash iter.Next() -> iter.Value(); iter++; | |||
csGetTicks() -> time(0) Need to #include <ctime> NOTE: if you need seconds then is ok to use this one | |||
csGetTicks() -> GetWorld()->GetRealTimeSeconds() OR GetWorld()->GetTimeSeconds() NOTE: if you need to use milliseconds use this one | |||
csMax(a, b); -> a > b ? a : b; | |||
csMin(a, b); -> a < b ? a : b; | |||
csQsqrt(x) -> FMath::Sqrt(x) | |||
csSet.Add() -> TArray.AddUnique(); | |||
csSquaredDist::PointLine() -> psPath::DistPointLine | |||
csStringArray.FindCaseInsensitive() -> Find (but is case sensitive).... no solution atm | |||
csTuple.first -> TPair.Key | |||
csTuple.second -> TPair.Value | |||
csVector.Norm() -> FVector.Size() calculates the magnitude/norm of the vector. | |||
csVector.SquaredNorm() -> FVector.SizeSquared() | |||
csVector v1 * v2 -> FVector::DotProduct(v1,v2) | |||
csVector.Unit() -> FVector.GetSafeNormal() | |||
output.Insert(0, time_buffer) -> output.InsertAt(0, time_buffer) | output.Insert(0, time_buffer) -> output.InsertAt(0, time_buffer) | ||
Line 59: | Line 331: | ||
Cross platform types are defined in Platform.h , like uint32. Those can be included with #include "EngineMinimal.h" | Cross platform types are defined in Platform.h , like uint32. Those can be included with #include "EngineMinimal.h" | ||
(!! Please note that CS_ASSERT are not enabled in PSLegacy production database, those are skipped !!) | |||
CS_ASSERT() -> check() | CS_ASSERT() -> check() | ||
CS_ASSERT_MSG() -> checkf(expr, TEXT("%s caused the error"), str); | |||
strcasecmp and strcmp, I added those two defines, so the code can stay as it is | strcasecmp and strcmp, I added those two defines, so the code can stay as it is | ||
Line 66: | Line 342: | ||
#define strcasecmp(expr1,expr2) FCString::Strcmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0 | #define strcasecmp(expr1,expr2) FCString::Strcmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0 | ||
#define strcmp(expr1,expr2) FCString::Stricmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0 | #define strcmp(expr1,expr2) FCString::Stricmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0 | ||
time(NULL) -> FString buf = FDateTime().GetDate().ToString(); | |||
toString(pos) -> StrUtils::toString(pos); | |||
toString(pos, sector) -> StrUtils::toString(pos, sector); | |||
csArray<csString> splitTarget = psSplit(target, ':'); -> TArray<FString> splitTarget; target.ParseIntoArray(splitTarget, TEXT(":")); | |||
WordArray.GetInt(1) -> FCString::Atoi(*myarray[1]) | |||
WordArray.GetFloat(1) -> FCString::Atof(*myarray[1]) | |||
WordArray.GetString(2, str) -> FString str = TArray[2] | |||
WordArray.GetTail(1) -> StrUtils::GetTail(words, 1) | |||
WordArray.GetWords(2, 5) -> StrUtils::GetWords(words, 2, 5) | |||
PI -> PI | |||
TWO_PI -> TWO_PI (added to PSUnreal.h) | |||
Result result(db->Select("")) -> psResultSet result = db->Query("") | |||
db->Command("INSERT...%s %s %s", var1, var2, var3); -> FString cmdString = FString::Printf(TEXT("INSERT...%s %s %s"), var1, var2, var3)); db->Command(cmdString); | |||
result[0].GetUInt32(0); -> result[0].GetInt(0); | |||
client->GetClientNum() -> client->GetUniqueID() need to check if this is ok, documentation says the ID lives until the actor lives. | |||
psserver->GetConnections()->Find -> becomes (to be tested) | |||
FConstPlayerControllerIterator iter = actor->GetWorld()->GetPlayerControllerIterator(); | |||
while(iter) | |||
{ | |||
APlayerController* client = *iter; | |||
ApsCharacter *actor = (ApsCharacter*)client->GetPawn(); | |||
gemObject.GetPosition(pos, sector) -> ApsCharacter.GetActorLocation() | |||
gemActor.RangeTo(gemActor) -> ApsCharacter.GetDistanceTo(ApsCharacter) | |||
EscpXML(string) -> StrUtils::EscpXML(string) | |||
psserver->CheckAccess() -> cacheManager->GetCommandManager()->CheckAccess() | |||
cel->FindPlayerEntity(pid) -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindPlayerEntity(pid); | |||
gem->FindNearbyEntities(iSec, pos, 0, range); -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindNearbyEntities(iSec, pos, 0, range); | |||
gemSupervisor->FindObject(containerID) -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindObject(containerID) | |||
GetGEM()->FindItemEntity(idNum); -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindObject(itemID) | |||
=== Logging and Error Messages === | |||
Verbosity levels: | |||
* Fatal: Always prints s fatal error to console (and log file) and crashes (even if logging is disabled) | |||
* Error: Prints an error to console (and log file) | |||
* Warning: Prints a warning to console (and log file) | |||
* Display: Prints a message to console (and log file) | |||
* Log: Prints a message to a log file (does not print to console) | |||
* Verbose: Prints a verbose message to a log file (if Verbose logging is enabled for the given category) | |||
CPrintf(CON_CMDOUTPUT,str.GetDataSafe()); -> UE_LOG(LogTemp, Warning, TEXT("%s"), str); | CPrintf(CON_CMDOUTPUT,str.GetDataSafe()); -> UE_LOG(LogTemp, Warning, TEXT("%s"), str); | ||
CPrintf(CON_CMDOUTPUT,"name: %s",str.GetDataSafe()); -> UE_LOG(LogTemp, Warning, TEXT("name: %s"), str); | |||
CPrintf(CON_ERROR, "psItemStats::GetProperty(%s) failed\n",ptr); -> UE_LOG(LogTemp, Error, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr); | |||
Notify3(LOG_SPAWN,"Spawning item (%u) in %d ",item->GetItemID(),triggerticks -csGetTicks()); -> UE_LOG(LogSpawn, Warning, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr); | |||
Debug3(LOG_ITEM, 0, "Set location in parent %d for %u", location, GetUID()); -> UE_LOG(LogTemp, Log, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr); | |||
Error3("Failed to insert trait '%s'.\n",t->name.GetData()); -> UE_LOG(LogTemp, Error, TEXT("Failed to insert trait '%s' into location table for race %d.\n"), t->name, t->raceID); | |||
psserver->SendSystemError(...) -> | |||
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); | |||
client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_ERROR); | |||
psserver->SendSystemInfo(...) -> | |||
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); | |||
client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_INFO); | |||
psserver->SendSystemOK(...); -> | |||
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); | |||
client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_OK); | |||
psserver->SendSystemResult(...); -> | |||
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); | |||
client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_RESULT); | |||
=== FText and Localization === | === FText and Localization === | ||
FText is Unreal's class for user viewable strings. It is localizable. See https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/FText/index.html | FText is Unreal's class for user viewable strings. It is localizable. See https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/FText/index.html | ||
=== XML parsing === | |||
#include "XmlParser.h" | |||
iDocumentNode -> FXmlNode | |||
csRef<iDocument> doc=xml->CreateDocument(); | |||
const char* error =doc->Parse(buff); | |||
becomes | |||
FXmlFile File(FPaths::ProjectDir() + FString(PHONICS_LIST)); | |||
FXmlNode* root = File.GetRootNode(); | |||
if its parsing a string and not a file, script is an FString | |||
FXmlFile File(script, EConstructMethod::ConstructFromBuffer); | |||
FXmlNode* root = File.GetRootNode(); | |||
Finding a specific child node: root->GetNode("FAMILY_NAME"); -> FXmlNode *familyName = root->FindChildNode("FAMILY_NAME"); | |||
csRef<iDocumentNodeIterator> iter = attitudeNode->GetNodes("response"); -> | |||
TArray<FXmlNode *> responses = attitudeNode->GetChildrenNodes(); | |||
for (int i = 0; i < responses.Num(); i++) | |||
{ | |||
FXmlNode *responseNode = responses[i]; | |||
if (responseNode->GetTag().Equals("response")) { | |||
csRef<iDocumentNodeIterator> iter = topNode->GetNodes(); -> TArray<FXmlNode*> arr = topNode->GetChildrenNodes(); TArray<FXmlNode*>::TIterator iter = arr.CreateIterator(); | |||
csRef<iDocumentAttributeIterator> it = top->GetAttributes(); -> TArray<FXmlAttribute> attrs = top->GetAttributes(); for (int i=0;attrs.Num();i++) | |||
csString skillName = tmp->GetAttributeValue("name"); -> tmp->GetAttribute("name"); | |||
float value = children[i]->GetAttributeValueAsFloat("value"); -> float value = FCString::Atof(*children[i]->GetAttribute("value")); | |||
int cstr_id_material = node->GetAttributeValueAsInt( "mesh" ); -> int cstr_id_material = FCString::Atoi(*node->GetAttribute("mesh")); | |||
bool includeInventory = topNode->GetAttributeValueAsBool("inventory", false); -> bool includeInventory = topNode->GetAttribute("inventory").Equals("true") ? 1 : 0; | |||
id = node->GetContentsValueAsInt(); -> id = FCString::Atoi(*node->GetContent()); | |||
meshname = node->GetContentsValue(); -> meshname = node->GetContent(); | |||
posx = node->GetContentsValueAsFloat(); -> posx = FCString::Atof(*node->GetContent()); | |||
node->GetValue() -> node->GetTag() if applied to an element. | |||
=== Platform specific includes === | === Platform specific includes === | ||
Line 83: | Line 503: | ||
your stuff here | your stuff here | ||
#endif | #endif | ||
=== Converting psMessages === | |||
PlaneShift code is heavily based on messages send from client to server and viceversa. The typical way to communicate is to create a message and send it. Messages are specific classes, example: | |||
class psCharDeleteMessage : public psMessageCracker | |||
{ | |||
public: | |||
psCharDeleteMessage(const char* charNameToDel, uint32_t clientNum); | |||
psCharDeleteMessage(MsgEntry* message); | |||
... | |||
To convert the messages we use [https://wiki.unrealengine.com/RPC_Client_Server_Messages_Example this technique] | |||
When we have a SystemMessage like this: | |||
psSystemMessage newmsg(GetUniqueID(), ESystemMessageType::MSG_INFO_BASE, "%s dropped %s.", *fullName, *item->GetQuantityName()); | |||
newmsg.Multicast(GetMulticastClients(), 0, RANGE_TO_SELECT); | |||
should be changed to : | |||
FString msg = FString::Printf(TEXT("%s dropped %s."), *fullName, *item->GetQuantityName()); | |||
pawn->Multicast(msg, ESystemMessageType::MSG_INFO_BASE, false, RANGE_TO_SELECT); | |||
=== Object Mapping PSLegacy PSUnreal === | |||
[[File:Unrealengine gemObjects.png|800px]] |
Latest revision as of 00:03, 28 August 2022
Code convertion
Types
csArray<> -> TArray
csBox2 -> TArray<FVector2D>
If you need to have unique key-value pairs:
csHash<Value> -> TMap<int,Value>
csHash<Value,Key> -> TMap<Key,Value> (note the swap of Key and Value)
If you need have multiple values for the same key:
csHash<Value,Key> -> TMultiMap<Key,Value> (notice the swap of Key and Value)
csHashCompute(string) -> StrUtils::hashCompute(string)
csList -> TDoubleLinkedList
csMD5::Digest -> to be bettere analyzed, for now just temporary
csPDelArray<PhonicEntry> -> TArray<PhonicEntry*>; (note the pointer in UE)
csRandomGen -> FMath::FRandRange(low, high);
psGetRandom() -> FMath::FRandRange(0, 1); // CAREFUL: psGetRandom 0 <= num < 1 WHILE FRandRange 0 <= num <= 1
psserver->GetRandomRange(pos, range) -> (pos - range + FMath::FRandRange(0,1)*range*2)
If you want to generate Integer random then use FMath::RandRange(1,10) // Returns a random number >= Min and <= Max
psserver->rng->Get(100) -> FMath::FRandRange(0,100);
csRef<iDocumentNode> containerNode -> FXmlNode *containerNode
csRefArray<csString> -> TArray<FString*>
csRegExpMatcher -> FRegexPattern , FRegexMatcher (check msgmanager.cpp:234)
csSet -> TArray (but be careful about insertions as csSet.Add checks for uniqueness)
csString -> psString or FString
csStringSet -> StringSet ( #include "util/strset.h" )
csStringArray -> TArray<FString>
psStringArray -> TArray<FString>
csSquaredDist::PointPoint() -> FVector::Dist(v1,v2)
csTicks -> float (time_t can be used only when 100% sure we can use an integer and no convertion issues from float)
CS::Threading::AtomicOperations::Increment(&nextid); -> FThreadSafeCounter.Increment()
CS::Threading::MutexScopedLock ScopeLock(mutex); -> FCriticalSection mutex; FScopeLock ScopeLock(mutex);
csTuple2 -> TPair
csVector2 -> FIntPoint
csVector3 -> FVector
?? csSet -> TArray ??
uint -> uint32
uint32_t -> #include <stdint.h>
iResultRow -> psResultRow
StringIDValue -> int (is this a correct assumption?)
WordArray -> TArray<FString> with space separator. Verify if this assumption is enough
//WordArray words(trigger.GetString()); TArray<FString> words; trigger.ParseIntoArray(words, TEXT(" "), true);
iVFS -> not used in UE, just delete the reference.
CS::Utility::PriorityQueue<TaskEntry> -> TArray<TaskEntry> items; use items.Heapify() to order.
NPC -> psNPCBrain
Types conversion
FString to char* -> const char *myData = TCHAR_TO_ANSI(*NameString);
FString to TCHAR -> *myFString
char* to FString -> ANSI_TO_TCHAR(NameString);
int to FString -> FString::FromInt(myInt);
float to FString -> FString::SanitizeFloat(myFloat);
int32 MyShinyNewInt = FCString::Atoi(*TheString);
float MyShinyNewFloat = FCString::Atof(*TheString);
Functions on csString
csString csv.AppendFmt(",%d,%d", fs->faction->id, fs->score); -> csv.Append(FString::Printf(TEXT(",%d,%d"), fs->faction->id, fs->score));
csString.AppendFmtV(fmt, args) -> vsprintf(line, fmt, args); script.Append(line);
csString.Clear() -> Empty()
csString input.Collapse() -> output = StrUtils::Collapse(input)
csString.CompareNoCase() returns TRUE if equal -> FString.Compare("ADD", ESearchCase::IgnoreCase)==0 returns 0 if equal
csString.DeleteAt(start) -> FString.RemoveAt(start)
csString.DeleteAt(start,count) -> FString.RemoveAt(start,count)
csString str.Detach() -> TCHAR_TO_ANSI(*str) detaches the data from the csString
csString.Downcase() -> mystring = mystring.ToLower() (NOTE the assignment in UE)
csString.Find(search, pos, ignore_case) -> FString.Find(search, ESearchCase::IgnoreCase)
csString.FindLast('-') -> int pos; csString.FindLastChar('-', pos)
csString.FindLast('-', startposition) -> pos = csString.Find('-', pos)
csString end = resp.Find("]", start); -> int end = resp.Find("]",ESearchCase::IgnoreCase , ESearchDir::FromStart, start);
csString.Free() -> mystring = ""
csString.FindFirst ('a') -> int pos; FString.FindChar(' ',pos);
csString pos = script.FindFirst(';', start); -> pos = script.Find("]",ESearchCase::IgnoreCase , ESearchDir::FromStart, start);
script.FindStr("string") -> script.Find("string");
mystr.FindReplace (search, replace) -> mystr = mystr.Replace(search, replace); (NOTE the assignment in UE)
csString.FindSubString() -> FString.Find()
string.Format("hey %s", param) -> string = FString::Printf(TEXT("hey %s"), param) (NOTE the assignment in UE)
csString.GetAt(0) -> [0]
csString.GetData() -> TCHAR_TO_ANSI(*mystring)
csString.GetDataSafe() -> TCHAR_TO_ANSI(*mystring)
csString.Insert(pos, str) -> FString.InsertAt(pos, string)
csString.Length() -> Len()
csString.LTrim() -> FString.Trim()
csString.Replace(from, to) -> mystr = mystr.Replace(TEXT("fromtext"), *to); (NOTE the assignment in UE)
csString.ReplaceSubString(search, replace) -> mystr = mystr.Replace(search, replace) (NOTE the assignment in UE)
csString.ReplaceAll(search, replace) -> mystr = mystr.Replace(search, replace) (NOTE the assignment in UE)
csString.Slice(5) -> FString.RightChop(5); if there is only one parameter CS assumes the second to be -1, so the end of the string
csString.Slice(0,5) -> mystr = FString.Left(5);
csString.Slice(a,b) -> mystr = FString.Mid(a,b);
csString.Split(csStringArray& arr, char delim) -> FString.ParseIntoArray(arr,TEXT("."));
csString resp.SubString(saySegment,start,numchars); -> FString saySegment = resp.Mid(start, numchars);
csString resp.SubString(saySegment,start); -> FString saySegment = resp.RightChop(start);
csString response.StartsWith("<Examine>", true) -> response.StartsWith("<Examine>", ESearchCase::IgnoreCase) (true ignore case, false case sensitive)
csString.RTrim() -> FString.TrimTrailing()
csString xxx = mystring.Trim() -> FString.TrimStartAndEnd() (this one does NOT change the string in place)
csString : mystring.Trim() -> FString.TrimStartAndEndInline() (this one changes the string in place)
csString.Truncate(5) -> modifiedString = FString.Left(5)
csString.Upcase() -> FString.ToUpper()
const char *myData = str->GetData(); -> TArray<TCHAR> myData = str.GetCharArray();
psString.GetLine() scr.GetLine(start,line); -> line = StrUtils::GetLine(scr,start);
Functions other types
psserver->GetRandom() provides a number between 0.0 and 1.0 -> FMath::FRandRange(0.0, 1.0)
csRandomGen.Get() -> FMath::FRandRange(0.0, 1.0)
psserver->GetRandom(limit) -> provides a number between 0.0 and limit -> FMath::FRandRange(0.0, limit) If provided with float it returns a float, if int then returns int.
csPDelArray.GetSize() -> TArray.Num()
csPDelArray.Push() -> TArray.Add()
csArray.Delete(item) -> TArray.Remove(item)
csArray.DeleteAll() -> TArray.Empty()
csArray.DeleteIndex(i) -> TArray.RemoveAt(i)
csArray.DeleteIndexFast(i) -> TArray.RemoveAt(i)
csArray.Extract(index) -> item = TArray[index]; TArray.RemoveAt(index);
csArray.FindStr("str", start) -> end = StrUtils::FindStr(words, "str", start);
csArray.FormatPush("%d",i); -> TArray.Add(FString::Printf(TEXT("%d",i));
csArray.GetSize() -> TArray.Num();
csArray myarray.Merge(otherArray) -> TArray.Append(otherArray)
csArray myarray.Get(0) -> TArray myarray[0]
csArray.Insert(index, item) -> TArray.Insert(item, index); (note switch of order)
csArray.InsertSorted(item) -> TArray.Add(item); TArray.Sort();
csArray.IsEmpty() -> TArray.Num()==0
csArray.PushSmart(item) -> int found = TArray.Find(item); if (found == INDEX_NONE) TArray.Add(item);
csArray.Put(index, item) -> TArray.RemoveAt(index); TArray.Insert(item, index); (note switch of order)
csArray.ShrinkBestFit() -> TArray.Shrink();
csArray.SplitString(str, ',') -> str.ParseIntoArray(array, TEXT(","));
csArrayItemNotFound -> INDEX_NONE
csList.Delete(node) -> TDoubleLinkedList.RemoveNode(node)
csList.DeleteAll() -> TDoubleLinkedList.Empty()
csList.Front() -> TDoubleLinkedList.GetHead()
csList.IsEmpty() -> TDoubleLinkedList.Num()==0
csList.PushBack() -> TDoubleLinkedList.AddTail() adds an element at the end of the list
csList.PushFront() -> TDoubleLinkedList.AddHead() adds an element at the beginning of the list
csList attackList.PopFront() -> attackList.RemoveNode(attackList.GetHead()); deletes an element at the beginning
csList attackList.Pop() -> attackList.RemoveNode(attackList.GetTail()); deletes an element at the end of the list
csList values.PopBack() -> values.RemoveNode(values.GetTail()); Deletes the last element of the list
for(csList<psItem*>::Iterator newitemitr(newitem); newitemitr.HasNext();) ->
TDoubleLinkedList<ApsItem*>::TIterator i(itemlist.GetHead()); while (i) { ....}
csHash.Delete(id, item) -> If not using multimap then TMap.Remove(id);
csHash.DeleteAll() -> TMap.Empty()
csHash.DeleteAll(name) -> If used as TMap (meaning no duplicate keys -> TMap.Remove(name)
csHash.Get(key,fallback) -> TMap.FindRef(key)
csHash.GetAll(key) example: channelSubscribers.GetAll(key) ->
TArray<uint32_t> subscribers; channelSubscribers.GetKeys(subscribers); for(size_t i = 0; i < subscribers.Num(); i++) { // filter subscribers by given channelID if (subscribers[i] == channelID) {
csHash.GetElementPointer(name) -> TMap.Find(name);
csHash.GetSize() -> TMap.Num();
csHash.In() -> TMap.Contains()
CS::IsNaN() -> isnan()
csHash.Put(value, key) -> TMap.Add(value, key) (NOTE NO swap of parameters)
csHash.PutUnique() -> TMap.Add() (we should test if this is ok)
csHash<FactionStanding*, int>::GlobalIterator iter(factionstandings.GetIterator()); -> TMap<int, FactionStanding*>::TIterator iter = factionstandings.CreateIterator();
csHash if(iter.HasNext()) -> if(iter)
csHash iter.Next() -> iter.Value(); iter++;
csGetTicks() -> time(0) Need to #include <ctime> NOTE: if you need seconds then is ok to use this one
csGetTicks() -> GetWorld()->GetRealTimeSeconds() OR GetWorld()->GetTimeSeconds() NOTE: if you need to use milliseconds use this one
csMax(a, b); -> a > b ? a : b;
csMin(a, b); -> a < b ? a : b;
csQsqrt(x) -> FMath::Sqrt(x)
csSet.Add() -> TArray.AddUnique();
csSquaredDist::PointLine() -> psPath::DistPointLine
csStringArray.FindCaseInsensitive() -> Find (but is case sensitive).... no solution atm
csTuple.first -> TPair.Key
csTuple.second -> TPair.Value
csVector.Norm() -> FVector.Size() calculates the magnitude/norm of the vector.
csVector.SquaredNorm() -> FVector.SizeSquared()
csVector v1 * v2 -> FVector::DotProduct(v1,v2)
csVector.Unit() -> FVector.GetSafeNormal()
output.Insert(0, time_buffer) -> output.InsertAt(0, time_buffer)
output.GetAt(output.Length()-1) -> output [ output.Len()-1 ]
Cross platform types are defined in Platform.h , like uint32. Those can be included with #include "EngineMinimal.h"
(!! Please note that CS_ASSERT are not enabled in PSLegacy production database, those are skipped !!)
CS_ASSERT() -> check()
CS_ASSERT_MSG() -> checkf(expr, TEXT("%s caused the error"), str);
strcasecmp and strcmp, I added those two defines, so the code can stay as it is
#define strcasecmp(expr1,expr2) FCString::Strcmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0 #define strcmp(expr1,expr2) FCString::Stricmp( ANSI_TO_TCHAR(expr1), ANSI_TO_TCHAR(expr2)) == 0
time(NULL) -> FString buf = FDateTime().GetDate().ToString();
toString(pos) -> StrUtils::toString(pos);
toString(pos, sector) -> StrUtils::toString(pos, sector);
csArray<csString> splitTarget = psSplit(target, ':'); -> TArray<FString> splitTarget; target.ParseIntoArray(splitTarget, TEXT(":"));
WordArray.GetInt(1) -> FCString::Atoi(*myarray[1])
WordArray.GetFloat(1) -> FCString::Atof(*myarray[1])
WordArray.GetString(2, str) -> FString str = TArray[2]
WordArray.GetTail(1) -> StrUtils::GetTail(words, 1)
WordArray.GetWords(2, 5) -> StrUtils::GetWords(words, 2, 5)
PI -> PI
TWO_PI -> TWO_PI (added to PSUnreal.h)
Result result(db->Select("")) -> psResultSet result = db->Query("")
db->Command("INSERT...%s %s %s", var1, var2, var3); -> FString cmdString = FString::Printf(TEXT("INSERT...%s %s %s"), var1, var2, var3)); db->Command(cmdString);
result[0].GetUInt32(0); -> result[0].GetInt(0);
client->GetClientNum() -> client->GetUniqueID() need to check if this is ok, documentation says the ID lives until the actor lives.
psserver->GetConnections()->Find -> becomes (to be tested) FConstPlayerControllerIterator iter = actor->GetWorld()->GetPlayerControllerIterator(); while(iter) { APlayerController* client = *iter; ApsCharacter *actor = (ApsCharacter*)client->GetPawn();
gemObject.GetPosition(pos, sector) -> ApsCharacter.GetActorLocation()
gemActor.RangeTo(gemActor) -> ApsCharacter.GetDistanceTo(ApsCharacter)
EscpXML(string) -> StrUtils::EscpXML(string)
psserver->CheckAccess() -> cacheManager->GetCommandManager()->CheckAccess()
cel->FindPlayerEntity(pid) -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindPlayerEntity(pid);
gem->FindNearbyEntities(iSec, pos, 0, range); -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindNearbyEntities(iSec, pos, 0, range);
gemSupervisor->FindObject(containerID) -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindObject(containerID)
GetGEM()->FindItemEntity(idNum); -> ((APlaneshiftBaseGameMode*)GetWorld()->GetAuthGameMode())->FindObject(itemID)
Logging and Error Messages
Verbosity levels:
- Fatal: Always prints s fatal error to console (and log file) and crashes (even if logging is disabled)
- Error: Prints an error to console (and log file)
- Warning: Prints a warning to console (and log file)
- Display: Prints a message to console (and log file)
- Log: Prints a message to a log file (does not print to console)
- Verbose: Prints a verbose message to a log file (if Verbose logging is enabled for the given category)
CPrintf(CON_CMDOUTPUT,str.GetDataSafe()); -> UE_LOG(LogTemp, Warning, TEXT("%s"), str);
CPrintf(CON_CMDOUTPUT,"name: %s",str.GetDataSafe()); -> UE_LOG(LogTemp, Warning, TEXT("name: %s"), str);
CPrintf(CON_ERROR, "psItemStats::GetProperty(%s) failed\n",ptr); -> UE_LOG(LogTemp, Error, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr);
Notify3(LOG_SPAWN,"Spawning item (%u) in %d ",item->GetItemID(),triggerticks -csGetTicks()); -> UE_LOG(LogSpawn, Warning, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr);
Debug3(LOG_ITEM, 0, "Set location in parent %d for %u", location, GetUID()); -> UE_LOG(LogTemp, Log, TEXT("psItemStats::GetProperty(%s) failed\n"),ptr);
Error3("Failed to insert trait '%s'.\n",t->name.GetData()); -> UE_LOG(LogTemp, Error, TEXT("Failed to insert trait '%s' into location table for race %d.\n"), t->name, t->raceID);
psserver->SendSystemError(...) ->
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_ERROR);
psserver->SendSystemInfo(...) ->
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_INFO);
psserver->SendSystemOK(...); ->
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_OK);
psserver->SendSystemResult(...); ->
FString msg = FString::Printf(TEXT("You can't pick up %s."), *GetName()); client->ReceiveSystemMessage(msg, ESystemMessageType::MSG_RESULT);
FText and Localization
FText is Unreal's class for user viewable strings. It is localizable. See https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/FText/index.html
XML parsing
- include "XmlParser.h"
iDocumentNode -> FXmlNode
csRef<iDocument> doc=xml->CreateDocument(); const char* error =doc->Parse(buff);
becomes
FXmlFile File(FPaths::ProjectDir() + FString(PHONICS_LIST)); FXmlNode* root = File.GetRootNode();
if its parsing a string and not a file, script is an FString
FXmlFile File(script, EConstructMethod::ConstructFromBuffer); FXmlNode* root = File.GetRootNode();
Finding a specific child node: root->GetNode("FAMILY_NAME"); -> FXmlNode *familyName = root->FindChildNode("FAMILY_NAME");
csRef<iDocumentNodeIterator> iter = attitudeNode->GetNodes("response"); ->
TArray<FXmlNode *> responses = attitudeNode->GetChildrenNodes(); for (int i = 0; i < responses.Num(); i++) { FXmlNode *responseNode = responses[i]; if (responseNode->GetTag().Equals("response")) {
csRef<iDocumentNodeIterator> iter = topNode->GetNodes(); -> TArray<FXmlNode*> arr = topNode->GetChildrenNodes(); TArray<FXmlNode*>::TIterator iter = arr.CreateIterator();
csRef<iDocumentAttributeIterator> it = top->GetAttributes(); -> TArray<FXmlAttribute> attrs = top->GetAttributes(); for (int i=0;attrs.Num();i++)
csString skillName = tmp->GetAttributeValue("name"); -> tmp->GetAttribute("name");
float value = children[i]->GetAttributeValueAsFloat("value"); -> float value = FCString::Atof(*children[i]->GetAttribute("value"));
int cstr_id_material = node->GetAttributeValueAsInt( "mesh" ); -> int cstr_id_material = FCString::Atoi(*node->GetAttribute("mesh"));
bool includeInventory = topNode->GetAttributeValueAsBool("inventory", false); -> bool includeInventory = topNode->GetAttribute("inventory").Equals("true") ? 1 : 0;
id = node->GetContentsValueAsInt(); -> id = FCString::Atoi(*node->GetContent());
meshname = node->GetContentsValue(); -> meshname = node->GetContent();
posx = node->GetContentsValueAsFloat(); -> posx = FCString::Atof(*node->GetContent());
node->GetValue() -> node->GetTag() if applied to an element.
Platform specific includes
If you want to include some code for a specific platform you can use:
- ifdef PLATFORM_WINDOWS
your stuff here
- endif
Converting psMessages
PlaneShift code is heavily based on messages send from client to server and viceversa. The typical way to communicate is to create a message and send it. Messages are specific classes, example:
class psCharDeleteMessage : public psMessageCracker { public: psCharDeleteMessage(const char* charNameToDel, uint32_t clientNum); psCharDeleteMessage(MsgEntry* message); ...
To convert the messages we use this technique
When we have a SystemMessage like this:
psSystemMessage newmsg(GetUniqueID(), ESystemMessageType::MSG_INFO_BASE, "%s dropped %s.", *fullName, *item->GetQuantityName()); newmsg.Multicast(GetMulticastClients(), 0, RANGE_TO_SELECT);
should be changed to :
FString msg = FString::Printf(TEXT("%s dropped %s."), *fullName, *item->GetQuantityName()); pawn->Multicast(msg, ESystemMessageType::MSG_INFO_BASE, false, RANGE_TO_SELECT);