UOX3 and cygwin (long; including patches for minor problems)

Want to discuss changes to the UOX3 source code? Got a code-snippet you'd like to post? Anything related to coding/programming goes here!
Post Reply
jr
UOX3 Newbie
Posts: 15
Joined: Mon Mar 07, 2005 1:40 pm
Location: Kiel
Has thanked: 0
Been thanked: 0

UOX3 and cygwin (long; including patches for minor problems)

Post by jr »

Last week - while I was on holiday cross country skiing in Norway - i checked out the impressive progress UOX has made since the last time I ran it under cygwin. It did require only minor changes and basically runs rock solid. I was using a Blacksmith/Miner character for testing.

Following is a short description of the minor problems encountered (all diffs
against anonymous CVS from about 060313 1500 GMT and NOT tested in a native windows build).

Ther was one crash problem due to my client configuration and the recent
CPIClientLanguage refactoring. I have

Code: Select all

  UserLanguageCodeString=enu
in my uo.cfg which triggered a bug in CPIClientLanguage::Receive(): which
(unlike UpdateLanguage() which is used ) neither upcases the string nor bothers to check the result of FindLanguage() and so results in an out-of-bounds-access later on. I've merged UpdateLanguage() handling into FindLanguage() so the latter always returns a useful result and removed the former. I'm not entirely happy with this (because language will be set even if it didn't change), but it fixes the problem. It would also be nice to import FindLanguage() by an appropriate header.

Code: Select all

Index: source/speech.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/speech.cpp,v
retrieving revision 1.15
diff -b -B -u -I\$$ -r1.15 speech.cpp
--- source/speech.cpp	9 Mar 2006 21:46:07 -0000	1.15
+++ source/speech.cpp	13 Mar 2006 15:38:38 -0000
@@ -117,23 +117,13 @@
 		codeLookup[LanguageCodes[(UnicodeTypes)i]] = (UnicodeTypes)i;
 }
 
-UnicodeTypes FindLanguage( const char *lang )
+UnicodeTypes FindLanguage( CSocket *s, int offset )
 {
-	std::map< std::string, UnicodeTypes >::const_iterator p = codeLookup.find( lang );
-	if( p != codeLookup.end() )
-		return p->second;
-	else
-		return TOTAL_LANGUAGES;
-}
-void UpdateLanguage( CSocket *s )
-{
-	if( s == NULL )
-		return;
 	char langCode[4];
 
-	langCode[0] = s->GetByte( 8 );
-	langCode[1] = s->GetByte( 9 );
-	langCode[2] = s->GetByte( 10 );
+	langCode[0] = s->GetByte( offset++ );
+	langCode[1] = s->GetByte( offset++ );
+	langCode[2] = s->GetByte( offset );
 	langCode[3] = 0;
 
 	UString ulangCode = langCode ;
@@ -142,11 +132,19 @@
 	UnicodeTypes cLang = s->Language();
 	if( LanguageCodes[cLang] != ulangCode.c_str() )
 	{
-		UnicodeTypes newLang = FindLanguage( ulangCode.c_str() );
-		if( newLang == TOTAL_LANGUAGES )
+		std::map< std::string, UnicodeTypes >::const_iterator p = codeLookup.find( ulangCode );
+		if( p != codeLookup.end() )
+		{
+			return p->second;
+		}
+		else
+		{
 			Console.Error( 0, "Unknown language type \"%s\".  PLEASE report this on www.sourceforge.net/projects/uox3 in the bugtracker!", ulangCode.c_str() );
+		}
+	}
 		else
-			s->Language( newLang );
+	{
+		return cLang;
 	} 
 }
Index: source/CPacketReceive.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/CPacketReceive.cpp,v
retrieving revision 1.27
diff -b -B -u -I\$$ -r1.27 CPacketReceive.cpp
--- source/CPacketReceive.cpp	12 Mar 2006 22:33:47 -0000	1.27
+++ source/CPacketReceive.cpp	13 Mar 2006 15:37:50 -0000
@@ -1497,7 +1497,7 @@
 //	The first 12 bits = the number of keywords present. The keywords are included right after this, each one is 12 bits also. 
 //	The keywords are padded to the closest byte. For example, if there are 2 keywords, it will take up 5 bytes. 12bits for the number, and 12 bits for each keyword. 12+12+12=36. Which will be padded 4 bits to 40 bits or 5 bytes.
 
-void UpdateLanguage( CSocket *s );
+UnicodeTypes FindLanguage( CSocket *s, int offset );
 
 CPITalkRequestUnicode::CPITalkRequestUnicode()
 {
@@ -1521,7 +1521,7 @@
 	textColour		= tSock->GetWord( 4 );
 	fontUsed		= tSock->GetWord( 6 );
 
-	UpdateLanguage( tSock );
+	tSock->Language (FindLanguage( tSock, 8 ));
 
 	CChar *mChar	= tSock->CurrcharObj();
 	mChar->setUnicode( true );
@@ -2173,7 +2173,6 @@
 //	UI16			subCmd;
 //	UI08			subSubCmd;
 
-UnicodeTypes FindLanguage( const char *lang );
 void PaperDoll( CSocket *s, CChar *pdoll );
 bool BuyShop( CSocket *s, CChar *c );
 
@@ -2442,7 +2441,7 @@
 
 void CPIClientLanguage::Receive( void )
 {
-	newLang = FindLanguage( (char *)&(tSock->Buffer()[5]) );
+	newLang = FindLanguage( tSock, 5 );
 }
 bool CPIClientLanguage::Handle( void )
 {
On *nix the code did only ever save the first account, because it didn't handle the EEXIST errno code (like the windows version does). I've unified error handling a bit and also made even real errors nonfatal where it seemed appropriate (e.g. when it could still successfully save the other accounts):

Code: Select all

Index: source/cAccountClass.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cAccountClass.cpp,v
retrieving revision 1.13
diff -b -B -u -I\$$ -r1.13 cAccountClass.cpp
--- source/cAccountClass.cpp	27 Feb 2006 07:50:14 -0000	1.13
+++ source/cAccountClass.cpp	13 Mar 2006 15:37:56 -0000
@@ -499,18 +499,18 @@
 			if( nDummy<0 )
 			{
 				// if directory exists then we just skip this.
-	#ifdef WIN32
-				if( GetLastError()!=183 )
+#ifdef WIN32
+				int errno = GetLastError();
+				if( errno!=183 )
+#else
+				if( errno!=EEXIST )
+#endif
 				{
+					Console.Error( 0, "CreateAccountSystem(): Couldn't create directory %s: errorcode %d", sNewPath.c_str(), errno);
 					m_mapUsernameIDMap.clear();
 					m_mapUsernameMap.clear();
 					return 0L;
 				}
-	#else
-				m_mapUsernameIDMap.clear();
-				m_mapUsernameMap.clear();
-				return 0L;
-	#endif
 			}
 			// Now open and copy the files. to their new location.
 			if( !actbTemp.sPath.length() )
@@ -709,13 +709,15 @@
 	{
 		// if directory exists then we just skip this.
 #ifdef WIN32
-		if( GetLastError()!=183 )
+		int errno = GetLastError();
+		if( errno!=183 )
+#else
+		if( errno!=EEXIST )
+#endif
 		{
+			Console.Error( 0, "AddAccount(): Couldn't create directory %s: errorcode %d", actbTemp.sPath.c_str(), errno);
 			return 0x0000;
 		}
-#else
-		return 0x0000;
-#endif
 	}
 	// Ok now thats finished. We need to do one last thing. Create the username.uad file in the account directory
 	std::string sUsernameUADPath(actbTemp.sPath);
@@ -1889,6 +1891,7 @@
 		if( actbID.sUsername != actbName.sUsername || actbID.sPassword != actbName.sPassword )
 		{
 			// there was an error between blocks
+			Console.Error( 0, "Save(): Mismatch %s - %s", actbID.sUsername.c_str(), actbName.sUsername.c_str() );
 			fsAccountsADM.close();
 			return 0xFFFF;
 		}
@@ -1940,13 +1943,16 @@
 		{
 			// if directory exists then we just skip this.
 #ifdef WIN32
-			if( GetLastError()!=183 )
-			{
-				return 0L;
-			}
+			int errno = GetLastError();
+			if( errno!=183 )
 #else
-			return 0L;
+			if( errno!=EEXIST )
 #endif
+			{
+				Console.Error( 0, "Save(): Couldn't create directory %s: errorcode  %d", actbID.sPath.c_str(), errno);
+				fsAccountsADM << "// !!! Couldn't save .uad file !!!" << std::endl;
+				continue;
+			}
 		}
 		// Ok now thats finished. We need to do one last thing. Create the username.uad file in the account directory
 		std::string sUsernameUADPath(actbID.sPath);
@@ -1968,7 +1974,9 @@
 		if( !fsAccountsUAD.is_open() )
 		{
 			// Ok we were unable to open the file so this user will not be added.
-			return 0x0000;
+			Console.Error( 0, "Save(): Couldn't open file %s", sUsernameUADPath.c_str());
+			fsAccountsADM << "// !!! Couldn't save .uad file !!!" << std::endl;
+			continue;
 		}
 		// Ok we have to write the new username.uad file in the directory
 		WriteUADHeader(fsAccountsUAD,actbID);
Bulletin board maintenance was also causing a server shutdown, because *nix cDirectoryListing::InternalRetrieve() was returning '..' as a file which was promptly deleted by the maintenance routine (when there is no active bulletin board). I've changed InternalRetrieve() to never return any directory entries (which AFAICS is different from the windows version, but it's working just fine).

Code: Select all

Index: source/cServerDefinitions.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cServerDefinitions.cpp,v
retrieving revision 1.14
diff -b -B -u -I\$$ -r1.14 cServerDefinitions.cpp
--- source/cServerDefinitions.cpp	16 Feb 2006 13:21:39 -0000	1.14
+++ source/cServerDefinitions.cpp	13 Mar 2006 15:38:20 -0000
@@ -530,14 +530,14 @@
 	while( ( dirp = readdir( dir ) ) ) 
 	{ 
 		stat( dirp->d_name, &dirstat ); 
-		if( S_ISDIR( dirstat.st_mode ) && doRecursion ) 
+		if( S_ISDIR( dirstat.st_mode ) )
 		{ 
-			if( strcmp( dirp->d_name, "." ) && strcmp( dirp->d_name, ".." ) ) 
+			if( strcmp( dirp->d_name, "." ) && strcmp( dirp->d_name, ".." ) && doRecursion )
 			{ 
 				subdirectories.push_back( cDirectoryListing( dirp->d_name, extension, doRecursion ) ); 
-				Console.Print( "%s/%s/n", currentDir.c_str(), dirp->d_name ); 
-				continue; 
 			} 
+			continue;
 		} 
 		shortList.push_back( dirp->d_name ); 
 		sprintf( filePath, "%s/%s", CurrentWorkingDir().c_str(), dirp->d_name ); 
Packet logging looks slightly funny on compilers with char defaulting to signed. Therefore I've changed the doPacketLogging() signature to UI08* and removed the casts to char*.

Code: Select all

Index: source/cSocket.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cSocket.cpp,v
retrieving revision 1.38
diff -b -B -u -I\$$ -r1.38 cSocket.cpp
--- source/cSocket.cpp	11 Mar 2006 19:50:06 -0000	1.38
+++ source/cSocket.cpp	13 Mar 2006 15:38:31 -0000
@@ -66,7 +66,7 @@
 	outStream << std::endl << std::endl;
 }
 
-void doPacketLogging( std::ofstream &outStream, size_t buffLen, const char *myBuffer )
+void doPacketLogging( std::ofstream &outStream, size_t buffLen, const UI08 *myBuffer )
 {
 	outStream << std::hex;
 	char qbuffer[8];
@@ -626,7 +626,7 @@
 			if( logDestination.is_open() )
 			{
 				logDestination << "[SEND]Packet: 0x" << (outbuffer[0] < 10?"0":"") << std::hex << (UI16)outbuffer[0] << "--> Length: " << std::dec << outlength << TimeStamp() << std::endl;
-				doPacketLogging( logDestination, outlength, (char *)outbuffer );
+				doPacketLogging( logDestination, outlength, outbuffer );
 				logDestination.close();
 			}
 			else
@@ -838,7 +838,7 @@
 		else
 		{
 			logDestination << "[RECV]Packet: 0x" << std::hex << (buffer[0] < 10?"0":"") << (UI16)buffer[0] << " --> Length: " << std::dec << inlength << TimeStamp() << std::endl;
-			doPacketLogging( logDestination, inlength, (char *)buffer );
+			doPacketLogging( logDestination, inlength, buffer );
 		}
 		logDestination.close();
 	}
@@ -1934,8 +1934,8 @@
 void CPUOXBuffer::Log( std::ofstream &outStream, bool fullHeader )
 {
 	if( fullHeader )
-		outStream << "[SEND]Packet: 0x" << (pStream.GetByte( 0 ) < 10?"0":"") << std::hex << (UI16)pStream.GetByte( 0 ) << "--> Length:" << std::dec << pStream.GetSize() << TimeStamp() << std::endl;
-	doPacketLogging( outStream, pStream.GetSize(), (char *)pStream.GetBuffer() );
+		outStream << "[SEND]Packet: 0x" << (pStream.GetByte( 0 ) < 16?"0":"") << std::hex << (UI16)pStream.GetByte( 0 ) << "--> Length:" << std::dec << pStream.GetSize() << TimeStamp() << std::endl;
+	doPacketLogging( outStream, pStream.GetSize(), pStream.GetBuffer() );
 }
 
 CPInputBuffer::CPInputBuffer() : tSock( NULL )
@@ -1950,8 +1950,8 @@
 	UI08 *buffer	= tSock->Buffer();
 	const UI32 len	= tSock->InLength();
 	if( fullHeader )
-		outStream << "[RECV]Packet Class Generic: 0x" << std::hex << (buffer[0] < 10?"0":"") << (UI16)buffer[0] << " --> Length: " << std::dec << len << TimeStamp() << std::endl;
-	doPacketLogging( outStream, len, (char *)buffer );
+		outStream << "[RECV]Packet Class Generic: 0x" << std::hex << (buffer[0] < 16?"0":"") << (UI16)buffer[0] << " --> Length: " << std::dec << len << TimeStamp() << std::endl;
+	doPacketLogging( outStream, len, buffer );
 }
 
 bool CPInputBuffer::Handle( void )
The following (minor) gameplay problems are not related to the cygwin build.

Popup information of worn items is only refreshed for the first item (typically weapon in right hand) due to a typo in PaperDoll(). (Actually I think an explicit iterator object would be cleaner)

Code: Select all

Index: source/cPlayerAction.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cPlayerAction.cpp,v
retrieving revision 1.59
diff -b -B -u -I\$$ -r1.59 cPlayerAction.cpp
--- source/cPlayerAction.cpp	10 Mar 2006 23:42:51 -0000	1.59
+++ source/cPlayerAction.cpp	13 Mar 2006 15:38:20 -0000
@@ -1507,7 +1512,7 @@
 		pd.FlagByte( 0x02 );
 	s->Send( &pd );
 
-	for( CItem *wearItem = pdoll->FirstItem(); !pdoll->FinishedItems(); pdoll->NextItem() )
+	for( CItem *wearItem = pdoll->FirstItem(); !pdoll->FinishedItems(); wearItem = pdoll->NextItem() )
 	{
 		if( ValidateObject( wearItem ) )
 		{
To have MakeOre() automagically fall back to ores with lower minskill if possible I've added sorting of orePreferences in order of descending minSkill to CTownRegion::InitFromScript().

Code: Select all

Index: source/townregion.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/townregion.cpp,v
retrieving revision 1.14
diff -b -B -u -I\$$ -r1.14 townregion.cpp
--- source/townregion.cpp	10 Mar 2006 23:42:51 -0000	1.14
+++ source/townregion.cpp	13 Mar 2006 15:38:45 -0000
@@ -315,6 +315,15 @@
 	return false;	// we're not in our town
 }
 
+bool oreSkillComparator (orePref o1, orePref o2)
+{
+	if (o1.oreIndex == NULL)
+		return false;
+	if (o2.oreIndex == NULL)
+		return true;
+	return o1.oreIndex->minSkill > o2.oreIndex->minSkill;
+}
+
 bool CTownRegion::InitFromScript( ScriptSection *toScan )
 {
 	UString tag;
@@ -542,6 +551,8 @@
 			orePreferences.push_back( toLoad );
 		}
 	}
+        // sort orePreferences in order of descending minSkill
+        std::sort (orePreferences.begin(), orePreferences.end(), oreSkillComparator);
 	return true;
 }
 
Mining itself had two problems: targeted Z coordinate wasn't extracted properly and the big ore handling was broken (because the item returned may actually be an already existing pile of ore in the pc's pack). (I've also slightly simplified the condition.)

Code: Select all

Index: source/skills.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/skills.cpp,v
retrieving revision 1.55
diff -b -B -u -I\$$ -r1.55 skills.cpp
--- source/skills.cpp	11 Mar 2006 19:50:06 -0000	1.55
+++ source/skills.cpp	13 Mar 2006 15:38:38 -0000
@@ -160,17 +160,21 @@
 		if( found == NULL )
 			continue;
 
-		if( sumChance > oreChance || oreChance < ( sumChance + toFind->percentChance ) )
+		sumChance += toFind->percentChance;
+		if( oreChance <= sumChance )
 		{
 			if( getSkill >= found->minSkill )
 			{
 				const std::string oreName	= found->name + " ore";
-				CItem *oreItem				= Items->CreateItem( &mSock, mChar, 0x19B9, 1, found->colour, OT_ITEM, true );
+				CItem *oreItem				= Items->CreateItem( &mSock, mChar, 0x19B9, ( RandomNum( 0, 100 ) > targRegion->GetChanceBigOre() ) ? 5 : 1, found->colour, OT_ITEM, true );
 				if( ValidateObject( oreItem ) )
 				{
 					oreItem->SetName( oreName );
-					if( RandomNum( 0, 100 ) > targRegion->GetChanceBigOre() )
-						oreItem->SetAmount( 5 );
 				}
 
 				mSock.sysmessage( 982, oreName.c_str() );
@@ -178,8 +182,6 @@
 				break;
 			}	
 		}
-
-		sumChance += toFind->percentChance;
 	}
 	if( !oreFound )
 	{
@@ -264,7 +281,7 @@
 
 	const SI16 targetX = mSock.GetWord( 11 );
 	const SI16 targetY = mSock.GetWord( 13 );
-	const SI08 targetZ = mSock.GetWord( 16 );
+	const SI08 targetZ = mSock.GetByte( 16 );
 
 	const SI16 distX = abs( mChar->GetX() - targetX );
 	const SI16 distY = abs( mChar->GetY() - targetY );
You may do with these changes whatever you like. Keep up the good work!
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Wow, alot to go through here!

I'll work on merging these changes into the CVS build right away, thanks jr, very glad to hear it's running well on cygwin!
Scott
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Merged (and tested) your changes under windows.

Only issue I got was the accounts stuff didn't like redeclaration of errno, so I simply used GetLastError() in the if statement (as EviL had done when he originally wrote it) under the Win32 ifdef.

Committing those changes (and the Signed DFN changes) to the CVS now, should appear on Anon CVS in a few hours.
Scott
User avatar
Xuri
Site Admin
Posts: 3704
Joined: Mon Jun 02, 2003 9:11 am
Location: Norway
Has thanked: 48 times
Been thanked: 8 times
Contact:

Post by Xuri »

jr wrote:Last week - while I was on holiday cross country skiing in Norway - i checked out the impressive progress UOX has made since the last time I ran it under cygwin. It did require only minor changes and basically runs rock solid. I was using a Blacksmith/Miner character for testing.
Nice work on the fixes =) Where in Norway were you skiing, btw? :P
-= Ho Eyo He Hum =-
jr
UOX3 Newbie
Posts: 15
Joined: Mon Mar 07, 2005 1:40 pm
Location: Kiel
Has thanked: 0
Been thanked: 0

Post by jr »

giwo wrote:Merged (and tested) your changes under windows.

Only issue I got was the accounts stuff didn't like redeclaration of errno, so I simply used GetLastError() in the if statement (as EviL had done when he originally wrote it) under the Win32 ifdef.

Committing those changes (and the Signed DFN changes) to the CVS now, should appear on Anon CVS in a few hours.
Thanks. Anon CVS access is pretty flaky currently, but I'll check it out ASAP (will try again in the morning when the US is still asleep :)
jr
UOX3 Newbie
Posts: 15
Joined: Mon Mar 07, 2005 1:40 pm
Location: Kiel
Has thanked: 0
Been thanked: 0

Post by jr »

Xuri wrote: Nice work on the fixes =) Where in Norway were you skiing, btw? :P
My sister in law didn't want to go to Gålå again (where our families were the last three years), so this year we went to Golsfjellet (at Ørterstølen). Not so much snow this year, but very nice cold weather. We did like it very much.
Grimson
Developer
Posts: 802
Joined: Sat Jun 04, 2005 1:52 am
Location: Germany
Has thanked: 0
Been thanked: 0

Post by Grimson »

jr wrote:Thanks. Anon CVS access is pretty flaky currently, but I'll check it out ASAP (will try again in the morning when the US is still asleep :)
Anon CVS is actually completely down: http://sourceforge.net/docs/A04/

I have uploaded the current sources here: http://rapidshare.de/files/15510111/uox ... 06.7z.html You'll need 7 Zip to decompress them.
jr
UOX3 Newbie
Posts: 15
Joined: Mon Mar 07, 2005 1:40 pm
Location: Kiel
Has thanked: 0
Been thanked: 0

Post by jr »

Grimson wrote: Anon CVS is actually completely down: http://sourceforge.net/docs/A04/

I have uploaded the current sources here: http://rapidshare.de/files/15510111/uox ... 06.7z.html You'll need 7 Zip to decompress them.
Thanks for the service , especially the link to the status page since I couldn't find it after the last redesign :oops:
Grimson
Developer
Posts: 802
Joined: Sat Jun 04, 2005 1:52 am
Location: Germany
Has thanked: 0
Been thanked: 0

Post by Grimson »

jr wrote:Thanks for the service
No problem.
jr wrote:especially the link to the status page since I couldn't find it after the last redesign :oops:
I can't find it eighter, but I still had a bookmark of it.
Post Reply