Thread

The AW SDK *IS* Thread-Safe! (Sdk)

The AW SDK *IS* Thread-Safe! // Sdk

1  |  

andon13

Apr 10, 2000, 10:38pm
Check this out . . . (Only relevant code has been pasted, because there's
over 120kb of code in the rest of this file, and besides, I don't distribute
full source code unless there's a good reason :)).



World List Sample : (Probably not Compilable, but the principle is clearly
visible)

UINT ONEMINUTE = 50;

CImageList m_ilWorlds;
CListCtrl m_Worlds;
LVITEM CheckIcon;
void UpdateWorldList (void);
UINT RedrawWorldList (LPVOID pParam);
UINT GenerateWorldList (LPVOID pParam);

int BGColor, WhisperColor, FriendColor, TouristColor, PSColor, AvatarColor;

CStringList PrvWrldName;
CStringList PubWrldName;
CStringList UnknownWrldName;
CStringList PrvWrldPop;
CStringList PubWrldPop;
CStringList UnknownWrldPop;

CTime LastUpdate;

bool bShowPrivate, bShowEmpty, bRunThread = true; // bShowPrivate and
bShowEmpty are read from the Registry using AfxGetApp()->GetProfileInt(...)
in OnInitDialog, and then converts them from INT to BOOL.

// ONEMINUTE is set to 60 seconds with SetTimer(...) in OnInitDialog . . .
(DUH!)

void CChatMonitor::OnTimer(UINT nIDEvent)
{
if ( nIDEvent == ONEMINUTE )
{
CTime CurrentTime = CTime::GetCurrentTime();
CTimeSpan NextUpdate = CurrentTime - LastUpdate;

if ( NextUpdate.GetMinutes() >= 5 && m_StatusTab.GetCurSel() == 1)
{
GetDlgItem(IDC_Worlds)->ShowWindow(SW_SHOW); // Makes sure the CListCtrl
is showing.
GetDlgItem(IDC_Worlds)->RedrawWindow(); // Some versions of the Common
Controls DLL require this, no idea why!?!?!?

AfxBeginThread(GenerateWorldList,NULL);
}
}

CResizingDialog::OnTimer(nIDEvent);
}

void CChatMonitor::UpdateWorldList(void) // Used to update the World List
from an External Class...
{ AfxBeginThread(GenerateWorldList,NULL); }

void CChatMonitor::SetWorldSettings (bool ShowEmpty, bool ShowPrivate)
{
bShowEmpty = ShowEmpty;
bShowPrivate = ShowPrivate;
}

UINT GenerateWorldList (LPVOID pParam)
{
if (!bRunThread)
return 0;

bRunThread = FALSE;

PubWrldName.RemoveAll(); // The following lines of code clear out any OLD
Worlds saved in the Linked Lists...
PubWrldPop.RemoveAll();
PrvWrldName.RemoveAll();
PrvWrldPop.RemoveAll();
UnknownWrldName.RemoveAll();
UnknownWrldPop.RemoveAll();

aw_event_set (AW_EVENT_WORLD_INFO, UpdateWorldList);
m_Worlds.DeleteAllItems();

int rc;
if (!rc = aw_world_list())
{
RedrawWorldList(NULL);
LastUpdate = CTime::GetCurrentTime();
}

else
{
LVCOLUMN ChangeTitle;
ChangeTitle.mask = LVCF_TEXT;
char NumberOfWorlds[10];
m_Worlds.InsertItem(0,"SDK Error",3);
CString ErrorNUM;
ErrorNUM.Format("%d",rc);
m_Worlds.SetItemText(0,1,ErrorNUM);
sprintf(NumberOfWorlds,"%d Error(s)",m_Worlds.GetItemCount());
ChangeTitle.pszText = NumberOfWorlds;
ChangeTitle.cchTextMax = sizeof(NumberOfWorlds);
m_Worlds.SetColumn(0,&ChangeTitle);
}

bRunThread = TRUE;
return 0;
}

void UpdateWorldList (void)
{
char Users[4];
sprintf(Users,"%d",aw_int(AW_WORLDLIST_USERS));

switch (aw_int (AW_WORLDLIST_STATUS))
{
case AW_WORLDSTATUS_PUBLIC:
PubWrldName.AddTail(aw_string (AW_WORLDLIST_NAME));
PubWrldPop.AddTail(Users);
break;

case AW_WORLDSTATUS_PRIVATE:
PrvWrldName.AddTail(aw_string (AW_WORLDLIST_NAME));
PrvWrldPop.AddTail(Users);
break;

default:
UnknownWrldName.AddTail(aw_string (AW_WORLDLIST_NAME));
UnknownWrldPop.AddTail(Users);
break;
}
}

UINT RedrawWorldList (LPVOID pParam)
{
m_Worlds.DeleteAllItems();

POSITION pName = PubWrldName.GetHeadPosition();
POSITION pPop = PubWrldPop.GetHeadPosition();
while( pName != NULL )
{
CString NextWorld = PubWrldName.GetNext( pName );
CString NextPop = PubWrldPop.GetNext( pPop );

int i = -1;
if (!NextWorld.CompareNoCase(aw_string(AW_WORLD_NAME))) // Done because in Build 15 of the SDK the AW_WORLD_NAME is lowercase . . .
i = m_Worlds.InsertItem (m_Worlds.GetItemCount(), NextWorld, 2);

else if (bShowEmpty || NextPop != "0")
i = m_Worlds.InsertItem (m_Worlds.GetItemCo
unt(), NextWorld, 0);

if (i != -1)
m_Worlds.SetItemText(i,1,NextPop);
}

if (bShowPrivate)
{
POSITION pName = PrvWrldName.GetHeadPosition();
POSITION pPop = PrvWrldPop.GetHeadPosition();
while( pName != NULL )
{
CString NextWorld = PrvWrldName.GetNext( pName );
CString NextPop = PrvWrldPop.GetNext( pPop );

int i = -1;
if (!NextWorld.CompareNoCase(aw_string(AW_WORLD_NAME))) // Done because
in Build 15 of the SDK the AW_WORLD_NAME is lowercase . . .
i = m_Worlds.InsertItem (m_Worlds.GetItemCount(), NextWorld, 2);

else if (bShowEmpty || NextPop != "0")
i = m_Worlds.InsertItem (m_Worlds.GetItemCount(), NextWorld, 1);

if (i != -1)
m_Worlds.SetItemText(i,1,NextPop);
}
}

LVCOLUMN ChangeTitle;
ChangeTitle.mask = LVCF_TEXT;
char NumberOfWorlds[10]; // Should probably be made into a dynamicaly sized
ptr, but I didn't want to waste my time, since as of now the number of
Worlds should never cause an Overflow in this, unless a bug occured.
sprintf(NumberOfWorlds,"%d Worlds",m_Worlds.GetItemCount());
ChangeTitle.pszText = NumberOfWorlds;
ChangeTitle.cchTextMax = sizeof(NumberOfWorlds);
m_Worlds.SetColumn(0,&ChangeTitle);

return 0;
}


Login Sample : (Probably not Compilable, but the principle is clearly
visible)

void CUltraBOTDlg::OnLogin()
{
UpdateData();

CString chNameCheck = chBotName;
chNameCheck.MakeLower();

if (nCitnum <= 1 || nCitnum >= 400000)
PlaySound("Audio/1stlaunch.wav",NULL,SND_ASYNC);

else if (chPassword.IsEmpty() || chPassword == "change_me")
PlaySound("Audio/Password.wav",NULL,SND_ASYNC);

else if (chNameCheck == "ultra bot" && nCitnum != 68992)
MessageBox("Sorry, but the name Ultra BOT is reserved for Andon13","Ultra
BOT --- Name Conflict", MB_ICONWARNING | MB_TOPMOST);

else
{
GetDlgItem(IDC_Login)->EnableWindow(false);
Connected = false;
PlaySound ("Audio/Logstart.wav",NULL,SND_ASYNC);
ChatMonitor.RemoveAllAvatars();
AvatarMap.ClearMap();

LoginStorage* ptp = new LoginStorage;
ptp->chPassword = chPassword;
ptp->chBotName = chBotName;
ptp->nCitnum = nCitnum;
ptp->nAV = nAvatar;
ptp->nX = nX;
ptp->nY = nY;
ptp->nYAW = nYAW;
ptp->nZ = nZ;
ptp->chWorldName = chWorld;
ptp->hWnd = m_hWnd;
AfxBeginThread (SecondThread, ptp);
}
}

UINT SecondThread (LPVOID pParam)
{
LoginStorage* ptp = (LoginStorage*) pParam;

CString chPassword = ptp->chPassword;
CString chBotName = ptp->chBotName;
CString chWorld = ptp->chWorldName;
int nAvatar = ptp->nAV;
int nX = ptp->nX;
int nY = ptp->nY;
int nZ = ptp->nZ;
int nYAW = ptp->nYAW;
int nCitnum = ptp->nCitnum;
HWND hWnd = ptp->hWnd;

delete ptp;

bool Success = Main.Login(nCitnum, chPassword, chBotName, chWorld, nX, nY, nZ, nYAW, nAvatar);
if (Success)
{
aw_event_set (AW_EVENT_AVATAR_ADD, handle_avatar_add);
aw_event_set (AW_EVENT_AVATAR_CHANGE, handle_avatar_change);
aw_event_set (AW_EVENT_AVATAR_DELETE, handle_avatar_delete);
aw_event_set (AW_EVENT_CHAT, handle_chat);
aw_event_set (AW_EVENT_AVATAR_CLICK, handle_avatar_click);
aw_event_set (AW_EVENT_WORLD_DISCONNECT, handle_world_disconnect);

CWnd::FromHandle(GetDlgItem(hWnd,IDC_Login))->ShowWindow(SW_HIDE);
CWnd::FromHandle(GetDlgItem(hWnd,IDC_Logoff))->ShowWindow(SW_SHOW);
}

else
CWnd::FromHandle(GetDlgItem(hWnd,IDC_Login))->EnableWindow(true);

return 0;
}

bool CUltraBOTDlg::Login (int nCitnum, /* Citizen Number */
CString chPassword, /* Password */
CString chBotName, /* Bot Name */
CString chWorld, /* World Name */
int nX, /* X Co-Ord */
int nY, /* Y Co-Ord */
int nZ, /* Z Co-Ord */
int nYAW, /* Angle */
int nAvatar) /* Avatar Number */
{
int rc;

Connected = false;

aw_destroy();

Status.Format("\r\n\r\n\r\nLogin Status:\r\nCreating Bot Instance . . .");
m_Status.SetWindowText(Status);
if (rc = aw_creat
e (chIP,nPort,0))
{
Login_Error (rc,"BOT Instance Creation Failed");
return false;
}

aw_int_set (AW_LOGIN_OWNER, nCitnum);
aw_string_set (AW_LOGIN_PRIVILEGE_PASSWORD, chPassword);
sprintf (message,"Ultra Bot %s",chVersion);
aw_string_set (AW_LOGIN_APPLICATION, message);
aw_string_set (AW_LOGIN_NAME, chBotName);
aw_int_set (AW_MY_X, nX);
aw_int_set (AW_MY_Y, nY);
aw_int_set (AW_MY_Z, nZ);
aw_int_set (AW_MY_YAW, nYAW);
aw_int_set (AW_MY_TYPE, nAvatar);
::nCitnum = nCitnum;
::chBotName = chBotName;
Whois = false;

Status.Format("\r\n\r\n\r\nLogin Status:\r\nConnecting to Universe . . .");
m_Status.SetWindowText(Status);
if (rc = aw_login ())
{
Login_Error (rc,"Universe Connect Failed");
return false;
}

Status.Format("\r\n\r\n\r\nLogin Status:\r\nConnecting to World . . .");
m_Status.SetWindowText(Status);
if (rc = aw_enter (chWorld,0))
{
Login_Error (rc,"World Connect Failed");
return false;
}

Status.Format("\r\n\r\n\r\nLogin Status:\r\nBinding to Avatar . . .");
m_Status.SetWindowText(Status);
if (rc = aw_state_change ())
{
Login_Error (rc,"Avatar Bind Failed");
return false;
}

else
{
PlaySound ("Audio/Logfinish.wav",NULL,SND_ASYNC);

LoginTime = CTime::GetCurrentTime();
Connected = true;

CTime StartTime = CTime::GetCurrentTime();
CString ChatTime = StartTime.Format("%B %#d, %Y at %#I:%M:%S %p (%Z)");

if (!ChatMonitor.bLogStarted)
{
CString ChatStart;
ChatStart.Format("Chat log started : %s",ChatTime);
ChatMonitor.Print2(ChatStart, RGB(0,0,0), 1, 0, 0, 0);
ChatMonitor.bLogStarted = true;
}

ChatMonitor.UpdateWorldList();
ChangeWorld();
return true;
}

return false;
}

CString CUltraBOTDlg::Login_Error (int m_nError, char m_chReply2[32])
{
Connected = false;

switch(m_nError)
{
case 1:sprintf (message,"Citizen number has expired");break;
case 3:sprintf (message,"Citizen number is invalid");break;
case 4:sprintf (message,"Message is too long");break;
case 5:sprintf (message,"Passwords cannot contain spaces");break;
case 6:sprintf (message,"Password is too long");break;
case 7:sprintf (message,"Password is too short");break;
case 8:sprintf (message,"Range too large");break;
case 9:sprintf (message,"Range too short");break;
case 10:sprintf (message,"Too many users");break;
case 11:sprintf (message,"Too few users");break;
case 12:sprintf (message,"RC_LICENSE_WORLD_CONTAINS_SPACE");break;
case 13:sprintf (message,"Invalid password");break;
case 14:sprintf (message,"RC_UNABLE_TO_MAIL_BACK_NUMBER");break;
case 15:sprintf (message,"RC_LICENSE_WORLD_TOO_SHORT");break;
case 16:sprintf (message,"RC_LICENSE_WORLD_TOO_LONG");break;
case 17:sprintf (message,"RC_SERVER_OUT_OF_MEMORY");break;
case 27:sprintf (message,"World is not running");break;
case 31:sprintf (message,"RC_NOT_LOGGED_IN");break;
case 32:sprintf (message,"RC_UNAUTHORIZED");break;
case 33:sprintf (message,"RC_ALREADY_LICENSED");break;
case 34:sprintf (message,"RC_NO_SUCH_LICENSE");break;
case 39:sprintf (message,"RC_IDENTITY_ALREADY_IN_USE");break;
case 40:sprintf (message,"RC_UNABLE_TO_REPORT_LOCATION");break;
case 41:sprintf (message,"RC_INVALID_EMAIL"); break;
case 42:sprintf (message,"Citizen number doesn't exist");break;
case 43:sprintf (message,"Invalid password");break;
case 58:sprintf (message,"Upgrade required");break;
case 59:sprintf (message,"BOT limit reached");break;
case 64:sprintf (message,"RC_LICENSE_STARTS_WITH_NUMBER");break;
case 66:sprintf (message,"RC_NO_SUCH_EJECTION");break;
case 67:sprintf (message,"No such session number");break;
case 100:sprintf (message,"RC_EMAIL_CONTAINS_INVALID_CHAR");break;
case 101:sprintf (message,"RC_EMAIL_ENDS_WITH_BLANK");break;
case 102:sprintf (message,"RC_EMAIL_MISSING_DOT");break;
case 103:sprintf (message,"RC_EMAIL_MISSING_AT");break;
case 104:sprintf (message,"RC_EMAIL_STARTS_WITH_BLANK");break;
case 105:sprintf (message,"RC_EMAIL_TOO_LONG");break;
case 106:sprintf (message,"RC_EMAIL_TOO_SHORT");break;
case 107:sprintf (message,"RC_NAME_ALREADY_USED");break;
case 108:sprintf (message,"RC_NAME_CONTAINS_INVALID_CHAR");break;
case 109:sprintf (message,"RC_NAME_CONTAINS_INVALID_BLANK");break;
case 110:sprintf (message,"RC_NAME_DOESNT_EXIST");break;
case 111:sprintf (message,"RC_NAME_ENDS_WITH_BLANK");break;
case 112:sprintf (message,"RC_NAME_TOO_LONG");break;
case 113:sprintf (message,"The name : %s, is too short", chBotName);break;
case 114:sprintf (message,"RC_NAME_UNUSED");break;
case 115:sprintf (message,"RC_PASSWORD_TOO_LONG");break;
case 116:sprintf (message,"RC_PASSWORD_TOO_SHORT");break;
case 117:sprintf (message,"RC_PASSWORD_IS_WRONG");break;
case 126:sprintf (message,"RC_NUMBER_ALREADY_USED");break;
case 127:sprintf (message,"RC_NUMBER_OUT_OF_RANGE");break;
case 128:sprintf (message,"Privilege password too short");break;
case 203:sprintf (message,"RC_NOT_CHANGE_OWNER");break;
case 204:sprintf (message,"RC_CANT_FIND_OLD_ELEMENT");break;
case 211:sprintf (message,"RC_CANT_CHANGE_OWNER");break;
case 216:sprintf (message,"RC_CANT_BUILD_HERE");break;
case 232:sprintf (message,"RC_NOT_ALLOWED");break;
case 300:sprintf (message,"RC_ENCROACHES");break;
case 301:sprintf (message,"RC_NO_SUCH_OBJECT");break;
case 302:sprintf (message,"RC_NOT_DELETE_OWNER");break;
case 303:sprintf (message,"RC_TOO_MANY_BYTES");break;
case 306:sprintf (message,"RC_UNREGISTERED_OBJECT");break;
case 308:sprintf (message,"RC_ELEMENT_ALREADY_EXISTS");break;
case 311:sprintf (message,"RC_NO_BUILD_RIGHTS");break;
case 313:sprintf (message,"Object outside of world property limits");break;
case 314:sprintf (message,"RC_RESTRICTED_OBJECT");break;
case 400:sprintf (message,"RC_OUT_OF_MEMORY");break;
case 401:sprintf (message,"RC_NOT_YET");break;
case 402:sprintf (message,"TIMEOUT");break;
case 403:sprintf (message,"RC_NULL_POINTER");break;
case 404:sprintf (message,"Unable to contact universe");break;
case 405:sprintf (message,"Unable to contact world");break;
case 406:sprintf (message,"Invalid world name");break;
case 415:sprintf (message,"RC_SEND_FAILED");break;
case 416:sprintf (message,"RC_RECEIVE_FAILED");break;
case 421:sprintf (message,"RC_STREAM_EMPTY");break;
case 422:sprintf (message,"RC_STREAM_MESSAGE_TOO_LONG");break;
case 423:sprintf (message,"World name too long");break;
case 426:sprintf (message,"Message too long");break;
case 429:sprintf (message,"Unable to connect to %s : %d",chIP,nPort);break;
case 439:sprintf (message,"No connection");break;
case 442:sprintf (message,"Unable to initialize network");break;
case 443:sprintf (message,"Incorrect_Message_Length");break;
case 444:sprintf (message,"RC_NOT_INITIALIZED");break;
case 445:sprintf (message,"No BOT instance exists.");break;
case 446:sprintf (message,"RC_OUT_BUFFER_FULL");break;
case 447:sprintf (message,"RC_INVALID_CALLBACK");break;
case 448:sprintf (message,"RC_INVALID_ATTRIBUTE");break;
case 449:sprintf (message,"RC_TYPE_MISMATCH");break;
case 450:sprintf (message,"RC_STRING_TOO_LONG");break;
case 451:sprintf (message,"RC_READ_ONLY");break;
case 453:sprintf (message,"RC_INVALID_INSTANCE");break;
case 454:
sprintf (message,"This version of Ultra BOT is ONLY compatible with AW.DLL
build %d",AW_BUILD);
GetDlgItem(IDC_Login)->EnableWindow(false); // Disables login because of
incorrect AW.DLL version.
break;
case 461:sprintf (message,"RC_IN_BUFFER_FULL");break;
case 463:sprintf (message,"RC_PROTOCOL_ERROR");break;
case 464:sprintf (message,"RC_QUERY_IN_PROGRESS");break;
case 466:sprintf (message,"I was ejected from this world.");break;
case 467:sprintf (message,"I am not allowed to enter this world.");break;
case 471:sprintf (message,"Internet connection lost");break;
case 474:sprintf (message,"RC_NOT_AVAILABLE");break;
default :sprintf (message,"Unknown Error (%d)!",m_nError);break;
}

PlaySound ("Audio/Error.wav",NULL,SND_ASYNC);
Status.Format("\r\n\r\n\r\n%s\r\n\r\nReason : %s",m_chReply2,message);
m_Status.SetWindowText(Status);

CString Returned;
Returned.Format("%s",message);
return Returned;
}


--- END ---
I didn't feel like defining the variables for the Login for ya, but I'll
give you this much . . .

typedef struct tagTHREADPARMS {
int nCitnum;
int nPort;
int nX;
int nY;
int nZ;
int nYAW;
int nAV;
CString chPassword;
CString chBotName;
CString chWorldName;
CString chIP;
HWND hWnd;
} LoginStorage;


And that should be all you need, if you're a "serious coder" :)

Best Regards,
Andon M. Coleman

Senior Programmer
R&D

Nothing, Inc.

P.S. Been using these methods for 6 months now . . . Left a BOT running with
this for over a month on my server, not a single crash! So it's pretty safe
to say that the AW SDK has proven to be Thread-Safe!

bigbadbear

Apr 11, 2000, 7:33pm
I have one question about your code... Since it concerns real time, why
arent you using pointers instead of variables? That would increase/enhance
code manipulation and time.

agent1

Apr 14, 2000, 7:27pm
Pointers need to "point" to something :)

-Agent1


[View Quote]

1  |  
Awportals.com is a privately held community resource website dedicated to Active Worlds.
Copyright (c) Mark Randall 2006 - 2024. All Rights Reserved.
Awportals.com   ·   ProLibraries Live   ·   Twitter   ·   LinkedIn