diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.h b/desmume/src/frontend/cocoa/cocoa_cheat.h index f3de1fd9e..0bc458cba 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.h +++ b/desmume/src/frontend/cocoa/cocoa_cheat.h @@ -24,6 +24,7 @@ class CHEATS; class CHEATS_LIST; class CHEATSEARCH; +class ClientCheatManager; enum CheatType { @@ -52,12 +53,13 @@ enum CheatSystemError class ClientCheatItem { protected: + ClientCheatManager *_cheatManager; + bool _isEnabled; bool _willAddFromDB; CheatType _cheatType; std::string _descriptionString; - void *_clientData; // Internal cheat type parameters CheatFreezeType _freezeType; @@ -81,6 +83,9 @@ public: void Init(const CHEATS_LIST &inCheatItem); void Init(const ClientCheatItem &inCheatItem); + void SetCheatManager(ClientCheatManager *cheatManager); + ClientCheatManager* GetCheatManager() const; + void SetEnabled(bool theState); bool IsEnabled() const; @@ -111,6 +116,7 @@ public: void SetRawCodeString(const char *rawString, const bool willSaveValidatedRawString); const char* GetRawCodeString() const; const char* GetCleanCodeString() const; + const std::string& GetCleanCodeCppString() const; uint32_t GetCodeCount() const; void ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const; @@ -118,9 +124,11 @@ public: class ClientCheatList { +private: + ClientCheatItem* __AddItem(const ClientCheatItem *srcItem, const bool willCopy, const bool allowDuplicates); + protected: std::vector *_list; - bool _engineNeedsUpdate; public: ClientCheatList(); @@ -129,41 +137,97 @@ public: CheatSystemError LoadFromFile(const char *filePath); CheatSystemError SaveToFile(const char *filePath); + bool IsItemDuplicate(const ClientCheatItem *srcItem); + ClientCheatItem* AddNew(); - ClientCheatItem* Add(ClientCheatItem *srcItem); - ClientCheatItem* AddNoDuplicate(ClientCheatItem *srcItem); - void Remove(ClientCheatItem *targetItem); - void RemoveAtIndex(size_t index); + ClientCheatItem* AddNewItemCopy(const ClientCheatItem *srcItem); + ClientCheatItem* AddNewItemCopyNoDuplicate(const ClientCheatItem *srcItem); + ClientCheatItem* AddExistingItemNoDuplicate(const ClientCheatItem *srcItem); + + bool Remove(ClientCheatItem *targetItem); + bool RemoveAtIndex(size_t index); void RemoveAll(); - void Update(const ClientCheatItem &srcItem, ClientCheatItem *targetItem); - ClientCheatItem* UpdateAtIndex(const ClientCheatItem &srcItem, size_t index); + + bool Update(const ClientCheatItem &srcItem, ClientCheatItem *targetItem); + bool UpdateAtIndex(const ClientCheatItem &srcItem, size_t index); size_t GetTotalCheatCount() const; size_t GetActiveCheatCount() const; std::vector* GetCheatList() const; + size_t GetIndexOfItem(const ClientCheatItem *cheatItem) const; ClientCheatItem* GetItemAtIndex(size_t index) const; void ReplaceFromEngine(const CHEATS *engineCheatList); void CopyListToEngine(const bool willApplyOnlyEnabledItems, CHEATS *engineCheatList); - void ApplyListToEngine(); - - static CHEATS* GetMasterCheatList(); }; -/******************************************************************************************** - CocoaDSCheatItem - OBJECTIVE-C CLASS +class ClientCheatManager +{ +protected: + ClientCheatList *_workingList; + ClientCheatList *_databaseList; + ClientCheatItem *_selectedItem; + size_t _selectedItemIndex; + uint32_t _untitledCount; + + std::string _databaseTitle; + std::string _databaseDate; + std::string _lastFilePath; + + bool _masterNeedsUpdate; + +public: + ClientCheatManager(); + ~ClientCheatManager(); + + static CHEATS* GetMaster(); + static void SetMaster(const CHEATS *masterCheats); + + ClientCheatList* GetWorkingList() const; + ClientCheatList* GetDatabaseList() const; + + const char* GetDatabaseTitle() const; + void SetDatabaseTitle(const char *dbTitle); + + const char* GetDatabaseDate() const; + void SetDatabaseDate(const char *dbDate); + + const char* GetLastFilePath() const; + + virtual CheatSystemError LoadFromFile(const char *filePath); + virtual CheatSystemError SaveToFile(const char *filePath); + + ClientCheatItem* SetSelectedItemByIndex(size_t index); + + ClientCheatItem* NewItem(); + ClientCheatItem* AddExistingItemNoDuplicate(const ClientCheatItem *theItem); + + void RemoveItem(ClientCheatItem *theItem); + void RemoveItemAtIndex(size_t index); + void RemoveSelectedItem(); + + void ModifyItem(const ClientCheatItem *srcItem, ClientCheatItem *targetItem); + void ModifyItemAtIndex(const ClientCheatItem *srcItem, size_t index); + + size_t GetTotalCheatCount() const; + size_t GetActiveCheatCount() const; + + ClientCheatList* LoadFromDatabase(const char *dbFilePath); + + void LoadFromMaster(); + void ApplyToMaster(); + void MasterNeedsUpdate(); + + void ApplyInternalCheatAtIndex(size_t index); + static void ApplyInternalCheatWithItem(const ClientCheatItem *cheatItem); + static void ApplyInternalCheatWithParams(uint32_t targetAddress, uint32_t newValue, size_t newValueLength); +}; - This is an Objective-C wrapper class for DeSmuME's cheat item struct. - - The cheat item data is not freed upon release of this object. This is by design. - - Thread Safety: - Assume that all methods are not thread-safe. This was done for performance - reasons. The caller of this class' methods is expected to handle thread safety. - ********************************************************************************************/ @interface CocoaDSCheatItem : NSObject { ClientCheatItem *_internalData; + BOOL _didAllocateInternalData; + BOOL _disableWorkingCopyUpdate; BOOL willAdd; CocoaDSCheatItem *workingCopy; @@ -190,8 +254,8 @@ public: @property (readonly) CocoaDSCheatItem *workingCopy; @property (assign) CocoaDSCheatItem *parent; -- (id) initWithCheatItem:(ClientCheatItem *)cheatItem; - (id) initWithCocoaCheatItem:(CocoaDSCheatItem *)cdsCheatItem; +- (id) initWithCheatItem:(ClientCheatItem *)cheatItem; - (id) initWithCheatData:(const CHEATS_LIST *)cheatData; - (char *) descriptionCString; - (void) update; @@ -208,49 +272,31 @@ public: @end -/******************************************************************************************** - CocoaDSCheatManager - OBJECTIVE-C CLASS - - This is an Objective-C wrapper class for DeSmuME's cheat list class. - - Thread Safety: - All methods are thread-safe. - ********************************************************************************************/ @interface CocoaDSCheatManager : NSObject { - ClientCheatList *_clientListData; + ClientCheatManager *_internalCheatManager; NSMutableArray *list; - - NSUInteger untitledCount; - NSString *dbTitle; - NSString *dbDate; - NSURL *lastFileURL; } -@property (readonly, nonatomic, getter=clientListData) ClientCheatList *_clientListData; +@property (readonly, nonatomic, getter=internalManager) ClientCheatManager *_internalCheatManager; @property (readonly) NSMutableArray *list; -@property (assign) NSUInteger untitledCount; -@property (copy) NSString *dbTitle; -@property (copy) NSString *dbDate; -@property (retain) NSURL *lastFileURL; +@property (assign, nonatomic) NSString *dbTitle; +@property (assign, nonatomic) NSString *dbDate; - (id) initWithFileURL:(NSURL *)fileURL; -- (BOOL) add:(CocoaDSCheatItem *)cheatItem; +- (CocoaDSCheatItem *) newItem; +- (BOOL) addExistingItem:(CocoaDSCheatItem *)cheatItem; - (void) remove:(CocoaDSCheatItem *)cheatItem; - (BOOL) update:(CocoaDSCheatItem *)cheatItem; - (BOOL) save; - (NSUInteger) activeCount; - (NSMutableArray *) cheatListFromDatabase:(NSURL *)fileURL errorCode:(NSInteger *)error; - (void) applyInternalCheat:(CocoaDSCheatItem *)cheatItem; -- (void) loadFromEngine; -- (void) applyListToEngine; +- (void) loadFromMaster; +- (void) applyToMaster; -+ (void) applyInternalCheatWithItem:(CocoaDSCheatItem *)cheatItem; -+ (void) applyInternalCheatWithAddress:(UInt32)address value:(UInt32)value bytes:(NSUInteger)bytes; -+ (NSMutableArray *) cheatListWithListObject:(CHEATS *)cheatList; + (NSMutableArray *) cheatListWithClientListObject:(ClientCheatList *)cheatList; -+ (NSMutableArray *) cheatListWithItemStructArray:(CHEATS_LIST *)cheatItemArray count:(NSUInteger)itemCount; @end diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.mm b/desmume/src/frontend/cocoa/cocoa_cheat.mm index 56ff7fb12..2e3bc2dd8 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.mm +++ b/desmume/src/frontend/cocoa/cocoa_cheat.mm @@ -122,14 +122,63 @@ size_t CheatConvertCleanCodeToRawCode(const char *inCleanCodeString, std::string return codeCount; } +bool IsCheatItemDuplicate(const ClientCheatItem *first, const ClientCheatItem *second) +{ + bool isDuplicate = false; + + if ( (first == NULL) || (second == NULL) ) + { + return isDuplicate; + } + + if (first == second) + { + isDuplicate = true; + return isDuplicate; + } + + const CheatType compareType = first->GetType(); + + switch (compareType) + { + case CheatType_Internal: + { + if ( (first->GetAddress() == second->GetAddress()) && + (first->GetValueLength() == second->GetValueLength()) && + (first->GetValue() == second->GetValue()) ) + { + isDuplicate = true; + } + break; + } + + case CheatType_ActionReplay: + { + if ( (first->GetCodeCount() == second->GetCodeCount()) && + (first->GetCleanCodeCppString() == second->GetCleanCodeCppString()) ) + { + isDuplicate = true; + } + break; + } + + case CheatType_CodeBreaker: + default: + break; + } + + return isDuplicate; +} + ClientCheatItem::ClientCheatItem() { + _cheatManager = NULL; + _isEnabled = false; _willAddFromDB = false; _cheatType = CheatType_Internal; _descriptionString = "No description."; - _clientData = NULL; _freezeType = CheatFreezeType_Normal; _address = 0x02000000; strncpy(_addressString, "0x02000000", sizeof(_addressString)); @@ -205,8 +254,23 @@ void ClientCheatItem::Init(const ClientCheatItem &inCheatItem) } } +void ClientCheatItem::SetCheatManager(ClientCheatManager *cheatManager) +{ + this->_cheatManager = cheatManager; +} + +ClientCheatManager* ClientCheatItem::GetCheatManager() const +{ + return this->_cheatManager; +} + void ClientCheatItem::SetEnabled(bool theState) { + if ( (this->_isEnabled != theState) && (this->_cheatManager != NULL) ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_isEnabled = theState; } @@ -245,6 +309,11 @@ void ClientCheatItem::SetType(CheatType requestedType) return; } + if ( (this->_cheatType != requestedType) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_cheatType = requestedType; } @@ -290,6 +359,11 @@ void ClientCheatItem::SetFreezeType(CheatFreezeType theFreezeType) return; } + if ( (this->_freezeType != theFreezeType) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_freezeType = theFreezeType; } @@ -305,6 +379,11 @@ uint32_t ClientCheatItem::GetAddress() const void ClientCheatItem::SetAddress(uint32_t theAddress) { + if ( (this->_address != theAddress) && (this->_cheatType == CheatType_Internal) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_address = theAddress; this->_addressString[0] = '0'; @@ -355,7 +434,16 @@ void ClientCheatItem::SetAddressSixDigitString(const char *sixDigitString) } this->_addressString[10] = '\0'; - sscanf(this->_addressString + 2, "%x", &this->_address); + + u32 theAddress = 0; + sscanf(this->_addressString + 2, "%x", &theAddress); + + if ( (this->_address != theAddress) && (this->_cheatType == CheatType_Internal) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + + this->_address = theAddress; if (this->_cheatType == CheatType_Internal) { @@ -370,6 +458,11 @@ uint32_t ClientCheatItem::GetValue() const void ClientCheatItem::SetValue(uint32_t theValue) { + if ( (this->_value != theValue) && (this->_cheatType == CheatType_Internal) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_value = theValue; if (this->_cheatType == CheatType_Internal) @@ -385,6 +478,11 @@ uint8_t ClientCheatItem::GetValueLength() const void ClientCheatItem::SetValueLength(uint8_t byteLength) { + if ( (this->_valueLength != byteLength) && (this->_cheatType == CheatType_Internal) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + this->_valueLength = byteLength; if (this->_cheatType == CheatType_Internal) @@ -419,6 +517,11 @@ void ClientCheatItem::SetRawCodeString(const char *rawString, const bool willSav this->_rawCodeString = rawString; } + if ( (this->_cheatType == CheatType_ActionReplay) && (this->_cheatManager != NULL) && this->_isEnabled ) + { + this->_cheatManager->MasterNeedsUpdate(); + } + if (this->_cheatType == CheatType_ActionReplay) { this->_ConvertActionReplayToInternal(); @@ -435,6 +538,11 @@ const char* ClientCheatItem::GetCleanCodeString() const return this->_cleanCodeString.c_str(); } +const std::string& ClientCheatItem::GetCleanCodeCppString() const +{ + return this->_cleanCodeString; +} + uint32_t ClientCheatItem::GetCodeCount() const { return this->_codeCount; @@ -544,7 +652,6 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const ClientCheatList::ClientCheatList() { _list = new std::vector; - _engineNeedsUpdate = true; } ClientCheatList::~ClientCheatList() @@ -597,92 +704,123 @@ CheatSystemError ClientCheatList::SaveToFile(const char *filePath) return error; } -ClientCheatItem* ClientCheatList::AddNew() -{ - this->_list->push_back(new ClientCheatItem); - return this->_list->back(); -} - -ClientCheatItem* ClientCheatList::Add(ClientCheatItem *srcItem) +bool ClientCheatList::IsItemDuplicate(const ClientCheatItem *srcItem) { + bool isDuplicateFound = false; if (srcItem == NULL) { - return NULL; + return isDuplicateFound; } - ClientCheatItem *newItem = this->AddNew(); - newItem->Init(*srcItem); + const CheatType compareType = srcItem->GetType(); - if (newItem->IsEnabled()) + const size_t totalCheatCount = this->_list->size(); + for (size_t i = 0; i < totalCheatCount; i++) { - this->_engineNeedsUpdate = true; + const ClientCheatItem *itemToCheck = (*this->_list)[i]; + if (itemToCheck == NULL) + { + continue; + } + + if (srcItem == itemToCheck) + { + isDuplicateFound = true; + break; + } + + switch (compareType) + { + case CheatType_Internal: + isDuplicateFound = ( (srcItem->GetAddress() == itemToCheck->GetAddress()) && + (srcItem->GetValue() == itemToCheck->GetValue()) && + (srcItem->GetValueLength() == itemToCheck->GetValueLength()) ); + break; + + case CheatType_ActionReplay: + isDuplicateFound = ( (srcItem->GetCodeCount() == itemToCheck->GetCodeCount()) && + (srcItem->GetCleanCodeCppString() == itemToCheck->GetCleanCodeCppString()) ); + break; + + case CheatType_CodeBreaker: + default: + break; + } + + if (isDuplicateFound) + { + break; + } + } + + return isDuplicateFound; +} + +ClientCheatItem* ClientCheatList::__AddItem(const ClientCheatItem *srcItem, const bool willCopy, const bool allowDuplicates) +{ + ClientCheatItem *newItem = NULL; + if (srcItem == NULL) + { + return newItem; + } + + if (allowDuplicates || !this->IsItemDuplicate(srcItem)) + { + if (willCopy) + { + this->_list->push_back(new ClientCheatItem); + newItem->Init(*srcItem); + } + else + { + this->_list->push_back((ClientCheatItem *)srcItem); + } + + newItem = this->_list->back(); } return newItem; } -ClientCheatItem* ClientCheatList::AddNoDuplicate(ClientCheatItem *srcItem) +ClientCheatItem* ClientCheatList::AddNew() { - bool isDuplicateFound = false; - ClientCheatItem *outNewItem = NULL; - - if (srcItem == NULL) - { - return outNewItem; - } - - const size_t cheatCount = this->_list->size(); - for (size_t i = 0; i < cheatCount; i++) - { - if ( (*this->_list)[i]->GetCleanCodeString() == srcItem->GetCleanCodeString() ) - { - isDuplicateFound = true; - break; - } - } - - if (!isDuplicateFound) - { - outNewItem = this->Add(srcItem); - } - - return outNewItem; + ClientCheatItem *newItem = new ClientCheatItem; + return this->__AddItem(newItem, false, true); } -void ClientCheatList::Remove(ClientCheatItem *targetItem) +ClientCheatItem* ClientCheatList::AddNewItemCopy(const ClientCheatItem *srcItem) { - if (targetItem == NULL) - { - return; - } - - const size_t cheatCount = this->_list->size(); - for (size_t i = 0; i < cheatCount; i++) - { - if (targetItem == (*this->_list)[i]) - { - this->RemoveAtIndex(i); - break; - } - } + return this->__AddItem(srcItem, true, true); } -void ClientCheatList::RemoveAtIndex(size_t index) +ClientCheatItem* ClientCheatList::AddNewItemCopyNoDuplicate(const ClientCheatItem *srcItem) { - if (index >= this->_list->size()) + return this->__AddItem(srcItem, true, false); +} + +ClientCheatItem* ClientCheatList::AddExistingItemNoDuplicate(const ClientCheatItem *srcItem) +{ + return this->__AddItem(srcItem, false, false); +} + +bool ClientCheatList::Remove(ClientCheatItem *targetItem) +{ + return this->RemoveAtIndex( this->GetIndexOfItem(targetItem) ); +} + +bool ClientCheatList::RemoveAtIndex(size_t index) +{ + bool didRemoveItem = false; + ClientCheatItem *targetItem = this->GetItemAtIndex(index); + + if (targetItem != NULL) { - return; + this->_list->erase( this->_list->begin() + index ); + delete targetItem; + didRemoveItem = true; } - ClientCheatItem *itemToRemove = (*this->_list)[index]; - - if (itemToRemove->IsEnabled()) - { - this->_engineNeedsUpdate = true; - } - - this->_list->erase( this->_list->begin() + index ); - delete itemToRemove; + return didRemoveItem; } void ClientCheatList::RemoveAll() @@ -691,50 +829,29 @@ void ClientCheatList::RemoveAll() for (size_t i = 0; i < cheatCount; i++) { ClientCheatItem *itemToRemove = (*this->_list)[i]; - - if (itemToRemove->IsEnabled()) - { - this->_engineNeedsUpdate = true; - } - delete itemToRemove; } this->_list->clear(); } -void ClientCheatList::Update(const ClientCheatItem &srcItem, ClientCheatItem *targetItem) +bool ClientCheatList::Update(const ClientCheatItem &srcItem, ClientCheatItem *targetItem) { - if (targetItem == NULL) - { - return; - } - - const size_t cheatCount = this->_list->size(); - for (size_t i = 0; i < cheatCount; i++) - { - if (targetItem == (*this->_list)[i]) - { - this->UpdateAtIndex(srcItem, i); - break; - } - } + return this->UpdateAtIndex(srcItem, this->GetIndexOfItem(targetItem)); } -ClientCheatItem* ClientCheatList::UpdateAtIndex(const ClientCheatItem &srcItem, size_t index) +bool ClientCheatList::UpdateAtIndex(const ClientCheatItem &srcItem, size_t index) { + bool didUpdateItem = false; ClientCheatItem *targetItem = this->GetItemAtIndex(index); if (targetItem != NULL) { targetItem->Init(srcItem); - if (targetItem->IsEnabled()) - { - this->_engineNeedsUpdate = true; - } + didUpdateItem = true; } - return targetItem; + return didUpdateItem; } size_t ClientCheatList::GetTotalCheatCount() const @@ -764,6 +881,26 @@ std::vector* ClientCheatList::GetCheatList() const return this->_list; } +size_t ClientCheatList::GetIndexOfItem(const ClientCheatItem *cheatItem) const +{ + size_t outIndex = ~0; + if (cheatItem == NULL) + { + return outIndex; + } + + const size_t cheatCount = this->_list->size(); + for (size_t i = 0; i < cheatCount; i++) + { + if (cheatItem == (*this->_list)[i]) + { + return outIndex; + } + } + + return outIndex; +} + ClientCheatItem* ClientCheatList::GetItemAtIndex(size_t index) const { if (index >= this->GetTotalCheatCount()) @@ -788,11 +925,6 @@ void ClientCheatList::ReplaceFromEngine(const CHEATS *engineCheatList) { ClientCheatItem *newItem = this->AddNew(); newItem->Init( *engineCheatList->getItemPtrAtIndex(i) ); - - if (newItem->IsEnabled()) - { - this->_engineNeedsUpdate = true; - } } } @@ -819,21 +951,394 @@ void ClientCheatList::CopyListToEngine(const bool willApplyOnlyEnabledItems, CHE } } -void ClientCheatList::ApplyListToEngine() +#pragma mark - + +ClientCheatManager::ClientCheatManager() { - CHEATS *engineCheatList = ClientCheatList::GetMasterCheatList(); - if ( (engineCheatList == NULL) || !this->_engineNeedsUpdate ) + _workingList = new ClientCheatList; + _databaseList = new ClientCheatList; + + _selectedItem = NULL; + _selectedItemIndex = 0; + + _untitledCount = 0; + + _databaseTitle.resize(0); + _databaseDate.resize(0); + _lastFilePath.resize(0); + + _masterNeedsUpdate = true; +} + +ClientCheatManager::~ClientCheatManager() +{ + delete this->_databaseList; + delete this->_workingList; +} + +CHEATS* ClientCheatManager::GetMaster() +{ + return cheats; +} + +void ClientCheatManager::SetMaster(const CHEATS *masterCheats) +{ + cheats = (CHEATS *)masterCheats; +} + +ClientCheatList* ClientCheatManager::GetWorkingList() const +{ + return this->_workingList; +} + +ClientCheatList* ClientCheatManager::GetDatabaseList() const +{ + return this->_databaseList; +} + +const char* ClientCheatManager::GetDatabaseTitle() const +{ + return this->_databaseTitle.c_str(); +} + +void ClientCheatManager::SetDatabaseTitle(const char *dbTitle) +{ + if (dbTitle != NULL) + { + this->_databaseTitle = dbTitle; + } +} + +const char* ClientCheatManager::GetDatabaseDate() const +{ + return this->_databaseDate.c_str(); +} + +void ClientCheatManager::SetDatabaseDate(const char *dbDate) +{ + if (dbDate != NULL) + { + this->_databaseDate = dbDate; + } +} + +const char* ClientCheatManager::GetLastFilePath() const +{ + return this->_lastFilePath.c_str(); +} + +CheatSystemError ClientCheatManager::LoadFromFile(const char *filePath) +{ + CheatSystemError error = CheatSystemError_NoError; + + if (filePath == NULL) + { + error = CheatSystemError_FileOpenFailed; + return error; + } + + error = this->_workingList->LoadFromFile(filePath); + if (error == CheatSystemError_NoError) + { + this->_lastFilePath = filePath; + + const size_t totalCount = this->_workingList->GetTotalCheatCount(); + for (size_t i = 0; i < totalCount; i++) + { + ClientCheatItem *cheatItem = this->_workingList->GetItemAtIndex(i); + cheatItem->SetCheatManager(this); + } + } + + return error; +} + +CheatSystemError ClientCheatManager::SaveToFile(const char *filePath) +{ + CheatSystemError error = CheatSystemError_NoError; + + if (filePath == NULL) + { + error = CheatSystemError_FileSaveFailed; + return error; + } + + error = this->_workingList->SaveToFile(filePath); + if (error == CheatSystemError_NoError) + { + this->_lastFilePath = filePath; + } + + return error; +} + +ClientCheatItem* ClientCheatManager::SetSelectedItemByIndex(size_t index) +{ + this->_selectedItemIndex = index; + this->_selectedItem = this->_workingList->GetItemAtIndex(index); + + return this->_selectedItem; +} + +ClientCheatItem* ClientCheatManager::NewItem() +{ + ClientCheatItem *newItem = this->_workingList->AddNew(); + newItem->SetCheatManager(this); + + this->_untitledCount++; + if (this->_untitledCount > 1) + { + char newDesc[16]; + snprintf(newDesc, sizeof(newDesc), "Untitled %ld", (unsigned long)this->_untitledCount); + + newItem->SetDescription(newDesc); + } + else + { + newItem->SetDescription("Untitled"); + } + + if (newItem->IsEnabled()) + { + this->_masterNeedsUpdate = true; + } + + return newItem; +} + +ClientCheatItem* ClientCheatManager::AddExistingItemNoDuplicate(const ClientCheatItem *theItem) +{ + ClientCheatItem *addedItem = this->_workingList->AddExistingItemNoDuplicate(theItem); + if (addedItem != NULL) + { + addedItem->SetCheatManager(this); + + if (addedItem->IsEnabled()) + { + this->_masterNeedsUpdate = true; + } + } + + return addedItem; +} + +void ClientCheatManager::RemoveItem(ClientCheatItem *targetItem) +{ + this->RemoveItemAtIndex( this->_workingList->GetIndexOfItem(targetItem) ); +} + +void ClientCheatManager::RemoveItemAtIndex(size_t index) +{ + const ClientCheatItem *targetItem = this->_workingList->GetItemAtIndex(index); + if (targetItem == NULL) { return; } - this->CopyListToEngine(true, engineCheatList); - this->_engineNeedsUpdate = false; + const bool willChangeMasterUpdateFlag = targetItem->IsEnabled(); + const bool didRemoveItem = this->_workingList->RemoveAtIndex(index); + + if (didRemoveItem && willChangeMasterUpdateFlag) + { + this->_masterNeedsUpdate = true; + } } -CHEATS* ClientCheatList::GetMasterCheatList() +void ClientCheatManager::RemoveSelectedItem() { - return cheats; + this->RemoveItemAtIndex(this->_selectedItemIndex); +} + +void ClientCheatManager::ModifyItem(const ClientCheatItem *srcItem, ClientCheatItem *targetItem) +{ + if ( (srcItem != NULL) && (srcItem == targetItem) ) + { + if (targetItem->IsEnabled()) + { + this->_masterNeedsUpdate = true; + } + return; + } + + this->ModifyItemAtIndex(srcItem, this->_workingList->GetIndexOfItem(targetItem)); +} + +void ClientCheatManager::ModifyItemAtIndex(const ClientCheatItem *srcItem, size_t index) +{ + const ClientCheatItem *targetItem = this->_workingList->GetItemAtIndex(index); + if ( (srcItem == NULL) || (targetItem == NULL) ) + { + return; + } + + const bool willChangeMasterUpdateFlag = targetItem->IsEnabled(); + const bool didModifyItem = this->_workingList->UpdateAtIndex(*srcItem, index); + + if (didModifyItem && willChangeMasterUpdateFlag) + { + this->_masterNeedsUpdate = true; + } +} + +size_t ClientCheatManager::GetTotalCheatCount() const +{ + return this->_workingList->GetTotalCheatCount(); +} + +size_t ClientCheatManager::GetActiveCheatCount() const +{ + return this->_workingList->GetActiveCheatCount(); +} + +ClientCheatList* ClientCheatManager::LoadFromDatabase(const char *dbFilePath) +{ + if (dbFilePath == NULL) + { + return NULL; + } + + CHEATSEXPORT *exporter = new CHEATSEXPORT(); + CheatSystemError dbError = CheatSystemError_NoError; + + bool didFileLoad = exporter->load((char *)dbFilePath); + if (didFileLoad) + { + this->_databaseList->RemoveAll(); + + this->SetDatabaseTitle((const char *)exporter->gametitle); + this->SetDatabaseDate((const char *)exporter->date); + + const size_t itemCount = exporter->getCheatsNum(); + const CHEATS_LIST *dbItem = exporter->getCheats(); + + for (size_t i = 0; i < itemCount; i++) + { + ClientCheatItem *newItem = this->_databaseList->AddNew(); + if (newItem != NULL) + { + newItem->Init(dbItem[i]); + } + } + } + else + { + dbError = (CheatSystemError)exporter->getErrorCode(); + } + + delete exporter; + exporter = nil; + + if (dbError != CheatSystemError_NoError) + { + return NULL; + } + + return this->_databaseList; +} + +void ClientCheatManager::LoadFromMaster() +{ + size_t activeCount = 0; + const CHEATS *masterCheats = ClientCheatManager::GetMaster(); + + if (masterCheats == NULL) + { + return; + } + + this->_lastFilePath = masterCheats->getFilePath(); + + activeCount = this->_workingList->GetActiveCheatCount(); + if (activeCount > 0) + { + this->_masterNeedsUpdate = true; + } + + this->_workingList->ReplaceFromEngine(masterCheats); + + const size_t totalCount = this->_workingList->GetTotalCheatCount(); + for (size_t i = 0; i < totalCount; i++) + { + ClientCheatItem *cheatItem = this->_workingList->GetItemAtIndex(i); + cheatItem->SetCheatManager(this); + } + + activeCount = this->_workingList->GetActiveCheatCount(); + if (activeCount > 0) + { + this->_masterNeedsUpdate = true; + } +} + +void ClientCheatManager::ApplyToMaster() +{ + CHEATS *masterCheats = ClientCheatManager::GetMaster(); + if ( (masterCheats == NULL) || !this->_masterNeedsUpdate ) + { + return; + } + + this->_workingList->CopyListToEngine(true, masterCheats); + this->_masterNeedsUpdate = false; +} + +void ClientCheatManager::MasterNeedsUpdate() +{ + this->_masterNeedsUpdate = true; +} + +void ClientCheatManager::ApplyInternalCheatAtIndex(size_t index) +{ + ClientCheatManager::ApplyInternalCheatWithItem( this->_workingList->GetItemAtIndex(index) ); +} + +void ClientCheatManager::ApplyInternalCheatWithItem(const ClientCheatItem *cheatItem) +{ + if ( (cheatItem == NULL) || (cheatItem->GetType() != CheatType_Internal) ) + { + return; + } + + ClientCheatManager::ApplyInternalCheatWithParams( cheatItem->GetAddress(), cheatItem->GetValue(), cheatItem->GetValueLength() ); +} + +void ClientCheatManager::ApplyInternalCheatWithParams(uint32_t targetAddress, uint32_t newValue, size_t newValueLength) +{ + targetAddress &= 0x00FFFFFF; + targetAddress |= 0x02000000; + + switch (newValueLength) + { + case 1: + { + u8 oneByteValue = (u8)(newValue & 0x000000FF); + _MMU_write08(targetAddress, oneByteValue); + break; + } + + case 2: + { + u16 twoByteValue = (u16)(newValue & 0x0000FFFF); + _MMU_write16(targetAddress, twoByteValue); + break; + } + + case 3: + { + u32 threeByteWithExtraValue = _MMU_read32(targetAddress); + threeByteWithExtraValue &= 0xFF000000; + threeByteWithExtraValue |= (newValue & 0x00FFFFFF); + _MMU_write32(targetAddress, threeByteWithExtraValue); + break; + } + + case 4: + _MMU_write32(targetAddress, newValue); + break; + + default: + break; + } } #pragma mark - @@ -864,7 +1369,12 @@ static NSImage *iconCodeBreaker = nil; - (id)init { - return [self initWithCheatData:nil]; + return [self initWithCheatItem:NULL]; +} + +- (id) initWithCocoaCheatItem:(CocoaDSCheatItem *)cdsCheatItem +{ + return [self initWithCheatItem:[cdsCheatItem clientData]]; } - (id) initWithCheatItem:(ClientCheatItem *)cheatItem @@ -875,31 +1385,26 @@ static NSImage *iconCodeBreaker = nil; return self; } - _internalData = new ClientCheatItem; + if (cheatItem == NULL) + { + _internalData = new ClientCheatItem; + _didAllocateInternalData = YES; + } + else + { + _internalData = cheatItem; + _didAllocateInternalData = NO; + } + _disableWorkingCopyUpdate = NO; willAdd = NO; workingCopy = nil; parent = nil; _isMemAddressAlreadyUpdating = NO; - if (cheatItem != NULL) - { - _internalData->Init(*cheatItem); - } - return self; } -- (id) initWithCocoaCheatItem:(CocoaDSCheatItem *)cdsCheatItem -{ - if (cdsCheatItem == nil) - { - return [self initWithCheatItem:NULL]; - } - - return [self initWithCheatItem:[cdsCheatItem clientData]]; -} - - (id) initWithCheatData:(const CHEATS_LIST *)cheatData { self = [super init]; @@ -909,6 +1414,7 @@ static NSImage *iconCodeBreaker = nil; } _internalData = new ClientCheatItem; + _didAllocateInternalData = YES; if (cheatData != NULL) { @@ -927,8 +1433,11 @@ static NSImage *iconCodeBreaker = nil; { [self destroyWorkingCopy]; - delete _internalData; - _internalData = NULL; + if (_didAllocateInternalData) + { + delete _internalData; + _internalData = NULL; + } [super dealloc]; } @@ -942,7 +1451,7 @@ static NSImage *iconCodeBreaker = nil; { _internalData->SetEnabled((theState) ? true : false); - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setEnabled:theState]; } @@ -964,7 +1473,7 @@ static NSImage *iconCodeBreaker = nil; _internalData->SetDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]); } - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setDescription:desc]; } @@ -1010,7 +1519,7 @@ static NSImage *iconCodeBreaker = nil; break; } - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setCheatType:theType]; } @@ -1065,7 +1574,7 @@ static NSImage *iconCodeBreaker = nil; { _internalData->SetFreezeType((CheatFreezeType)theType); - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setFreezeType:theType]; } @@ -1080,7 +1589,7 @@ static NSImage *iconCodeBreaker = nil; { _internalData->SetValueLength(byteSize); - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setBytes:byteSize]; } @@ -1113,7 +1622,7 @@ static NSImage *iconCodeBreaker = nil; [self setCodeCount:[self codeCount]]; [self setBytes:[self bytes]]; - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setCode:theCode]; } @@ -1139,7 +1648,7 @@ static NSImage *iconCodeBreaker = nil; _isMemAddressAlreadyUpdating = NO; } - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setMemAddress:theAddress]; } @@ -1161,7 +1670,7 @@ static NSImage *iconCodeBreaker = nil; _isMemAddressAlreadyUpdating = NO; } - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setMemAddressString:addressString]; } @@ -1186,7 +1695,7 @@ static NSImage *iconCodeBreaker = nil; { _internalData->SetValue((u32)theValue); - if (workingCopy != nil) + if ((workingCopy != nil) && !_disableWorkingCopyUpdate) { [workingCopy setValue:theValue]; } @@ -1218,6 +1727,11 @@ static NSImage *iconCodeBreaker = nil; return; } + if (cdsCheatItem == workingCopy) + { + _disableWorkingCopyUpdate = YES; + } + [self setEnabled:[cdsCheatItem enabled]]; [self setDescription:[cdsCheatItem description]]; [self setCheatType:[cdsCheatItem cheatType]]; @@ -1233,6 +1747,8 @@ static NSImage *iconCodeBreaker = nil; { [self setCode:[cdsCheatItem code]]; } + + _disableWorkingCopyUpdate = NO; } - (CocoaDSCheatItem *) createWorkingCopy @@ -1244,7 +1760,10 @@ static NSImage *iconCodeBreaker = nil; [workingCopy release]; } - newWorkingCopy = [[CocoaDSCheatItem alloc] initWithCocoaCheatItem:self]; + newWorkingCopy = [[CocoaDSCheatItem alloc] init]; + ClientCheatItem *workingCheat = [newWorkingCopy clientData]; + workingCheat->Init(*[self clientData]); + [newWorkingCopy setParent:self]; workingCopy = newWorkingCopy; @@ -1302,12 +1821,10 @@ static NSImage *iconCodeBreaker = nil; @implementation CocoaDSCheatManager -@synthesize _clientListData; +@synthesize _internalCheatManager; @synthesize list; -@synthesize untitledCount; -@synthesize dbTitle; -@synthesize dbDate; -@synthesize lastFileURL; +@dynamic dbTitle; +@dynamic dbDate; - (id)init { @@ -1322,64 +1839,96 @@ static NSImage *iconCodeBreaker = nil; return self; } - _clientListData = new ClientCheatList; + _internalCheatManager = new ClientCheatManager; if (fileURL != nil) { - lastFileURL = [fileURL copy]; - _clientListData->LoadFromFile([CocoaDSUtil cPathFromFileURL:lastFileURL]); - list = [[CocoaDSCheatManager cheatListWithClientListObject:_clientListData] retain]; + _internalCheatManager->LoadFromFile([CocoaDSUtil cPathFromFileURL:fileURL]); + + ClientCheatList *clientList = _internalCheatManager->GetWorkingList(); + list = [[CocoaDSCheatManager cheatListWithClientListObject:clientList] retain]; } else { list = [[NSMutableArray alloc] initWithCapacity:100]; if (list == nil) { - delete _clientListData; + delete _internalCheatManager; [self release]; return nil; } } - untitledCount = 0; - dbTitle = nil; - dbDate = nil; - return self; } - (void)dealloc { - [self setDbTitle:nil]; - [self setDbDate:nil]; - [list release]; list = nil; - [self setLastFileURL:nil]; - - delete _clientListData; - _clientListData = NULL; + delete _internalCheatManager; + _internalCheatManager = NULL; [super dealloc]; } -- (BOOL) add:(CocoaDSCheatItem *)cheatItem +- (NSString *) dbTitle +{ + return [NSString stringWithCString:_internalCheatManager->GetDatabaseTitle() encoding:NSUTF8StringEncoding]; +} + +- (void) setDbTitle:(NSString *)theString +{ + // Do nothing. This method exists for KVO compliance only. +} + +- (NSString *) dbDate +{ + return [NSString stringWithCString:_internalCheatManager->GetDatabaseDate() encoding:NSUTF8StringEncoding]; +} + +- (void) setDbDate:(NSString *)theString +{ + // Do nothing. This method exists for KVO compliance only. +} + +- (CocoaDSCheatItem *) newItem +{ + CocoaDSCheatItem *newCocoaItem = nil; + + ClientCheatItem *newItem = _internalCheatManager->NewItem(); + if (newItem == NULL) + { + return newCocoaItem; + } + + newCocoaItem = [[CocoaDSCheatItem alloc] initWithCheatItem:newItem]; + if (newCocoaItem == nil) + { + delete newItem; + newItem = NULL; + } + + return newCocoaItem; +} + +- (BOOL) addExistingItem:(CocoaDSCheatItem *)cheatItem { BOOL result = NO; - if (cheatItem == nil) + if ( (cheatItem == nil) || [[self list] containsObject:cheatItem] ) { return result; } - _clientListData->Add([cheatItem clientData]); - - if (![[self list] containsObject:cheatItem]) + ClientCheatItem *addedItem = _internalCheatManager->AddExistingItemNoDuplicate([cheatItem clientData]); + if (addedItem == NULL) { - [[self list] addObject:cheatItem]; + return result; } + result = YES; return result; } @@ -1396,9 +1945,7 @@ static NSImage *iconCodeBreaker = nil; return; } - _clientListData->RemoveAtIndex(selectionIndex); - - [[self list] removeObject:cheatItem]; + _internalCheatManager->RemoveItemAtIndex(selectionIndex); } - (BOOL) update:(CocoaDSCheatItem *)cheatItem @@ -1410,176 +1957,79 @@ static NSImage *iconCodeBreaker = nil; return result; } - NSUInteger selectionIndex = [[self list] indexOfObject:cheatItem]; - if (selectionIndex == NSNotFound) - { - return result; - } - - _clientListData->UpdateAtIndex(*[cheatItem clientData], selectionIndex); - + _internalCheatManager->ModifyItem([cheatItem clientData], [cheatItem clientData]); [cheatItem update]; + result = YES; return result; } - (BOOL) save { - const CheatSystemError error = _clientListData->SaveToFile([CocoaDSUtil cPathFromFileURL:[self lastFileURL]]); + const char *lastFilePath = _internalCheatManager->GetLastFilePath(); + const CheatSystemError error = _internalCheatManager->SaveToFile(lastFilePath); + return (error == CheatSystemError_NoError) ? YES : NO; } - (NSUInteger) activeCount { - return (NSUInteger)_clientListData->GetActiveCheatCount(); + return (NSUInteger)_internalCheatManager->GetActiveCheatCount(); } - (NSMutableArray *) cheatListFromDatabase:(NSURL *)fileURL errorCode:(NSInteger *)error { - NSMutableArray *newDBList = nil; + NSMutableArray *newCocoaDBList = nil; if (fileURL == nil) { - return newDBList; + return newCocoaDBList; } - CHEATSEXPORT *exporter = new CHEATSEXPORT(); - - BOOL result = exporter->load((char *)[CocoaDSUtil cPathFromFileURL:fileURL]); - if (!result) + ClientCheatList *dbList = _internalCheatManager->LoadFromDatabase([CocoaDSUtil cPathFromFileURL:fileURL]); + if (dbList != NULL) { - if (error != nil) - { - *error = exporter->getErrorCode(); - } + newCocoaDBList = [CocoaDSCheatManager cheatListWithClientListObject:dbList]; } - else - { - [self setDbTitle:[NSString stringWithCString:(const char *)exporter->gametitle encoding:NSUTF8StringEncoding]]; - [self setDbDate:[NSString stringWithCString:(const char *)exporter->date encoding:NSUTF8StringEncoding]]; - newDBList = [CocoaDSCheatManager cheatListWithItemStructArray:exporter->getCheats() count:exporter->getCheatsNum()]; - if (newDBList != nil) - { - for (CocoaDSCheatItem *cheatItem in newDBList) - { - [cheatItem setWillAdd:NO]; - } - } - } - - delete exporter; - exporter = nil; - return newDBList; + return newCocoaDBList; } - (void) applyInternalCheat:(CocoaDSCheatItem *)cheatItem -{ - [CocoaDSCheatManager applyInternalCheatWithItem:cheatItem]; -} - -- (void) loadFromEngine -{ - CHEATS *engineList = ClientCheatList::GetMasterCheatList(); - if (engineList != NULL) - { - NSString *cheatsPath = [NSString stringWithCString:engineList->getFilePath() encoding:NSUTF8StringEncoding]; - [self setLastFileURL:[NSURL fileURLWithPath:cheatsPath]]; - _clientListData->ReplaceFromEngine(engineList); - - if (list != nil) - { - [list release]; - } - - list = [[CocoaDSCheatManager cheatListWithClientListObject:_clientListData] retain]; - } -} - -- (void) applyListToEngine -{ - _clientListData->ApplyListToEngine(); -} - -+ (void) applyInternalCheatWithItem:(CocoaDSCheatItem *)cheatItem { if (cheatItem == nil) { return; } - [CocoaDSCheatManager applyInternalCheatWithAddress:[cheatItem memAddress] value:(u32)[cheatItem value] bytes:[cheatItem bytes]]; + ClientCheatManager::ApplyInternalCheatWithItem([cheatItem clientData]); } -+ (void) applyInternalCheatWithAddress:(UInt32)address value:(UInt32)value bytes:(NSUInteger)bytes +- (void) loadFromMaster { - address &= 0x00FFFFFF; - address |= 0x02000000; - - switch (bytes) + CHEATS *masterCheats = ClientCheatManager::GetMaster(); + if (masterCheats != NULL) { - case 1: - { - u8 oneByteValue = (u8)(value & 0x000000FF); - _MMU_write08(address, oneByteValue); - break; - } - - case 2: - { - u16 twoByteValue = (u16)(value & 0x0000FFFF); - _MMU_write16(address, twoByteValue); - break; - } - - case 3: - { - u32 threeByteWithExtraValue = _MMU_read32(address); - threeByteWithExtraValue &= 0xFF000000; - threeByteWithExtraValue |= (value & 0x00FFFFFF); - _MMU_write32(address, threeByteWithExtraValue); - break; - } - - case 4: - _MMU_write32(address, value); - break; - - default: - break; - } -} - -+ (NSMutableArray *) cheatListWithListObject:(CHEATS *)cheatList -{ - if (cheatList == nil) - { - return nil; - } - - NSMutableArray *newList = [NSMutableArray arrayWithCapacity:100]; - if (newList == nil) - { - return newList; - } - - size_t itemCount = cheatList->getListSize(); - for (size_t i = 0; i < itemCount; i++) - { - CocoaDSCheatItem *newItem = [[CocoaDSCheatItem alloc] initWithCheatData:cheatList->getItemPtrAtIndex(i)]; + _internalCheatManager->LoadFromMaster(); - if (newItem != nil) + if (list != nil) { - [newList addObject:[newItem autorelease]]; + [list release]; } + + ClientCheatList *clientList = _internalCheatManager->GetWorkingList(); + list = [[CocoaDSCheatManager cheatListWithClientListObject:clientList] retain]; } - - return newList; +} + +- (void) applyToMaster +{ + _internalCheatManager->ApplyToMaster(); } + (NSMutableArray *) cheatListWithClientListObject:(ClientCheatList *)cheatList { - if (cheatList == nil) + if (cheatList == NULL) { return nil; } @@ -1593,38 +2043,16 @@ static NSImage *iconCodeBreaker = nil; const size_t itemCount = cheatList->GetTotalCheatCount(); for (size_t i = 0; i < itemCount; i++) { - CocoaDSCheatItem *newItem = [[CocoaDSCheatItem alloc] initWithCheatItem:cheatList->GetItemAtIndex(i)]; - - if (newItem != nil) + CocoaDSCheatItem *cheatItem = [[CocoaDSCheatItem alloc] initWithCheatItem:cheatList->GetItemAtIndex(i)]; + if (cheatItem != nil) { - [newList addObject:[newItem autorelease]]; + [newList addObject:[cheatItem autorelease]]; } } return newList; } -+ (NSMutableArray *) cheatListWithItemStructArray:(CHEATS_LIST *)cheatItemArray count:(NSUInteger)itemCount -{ - if (cheatItemArray == nil) - { - return nil; - } - - NSMutableArray *newList = [NSMutableArray arrayWithCapacity:100]; - if (newList == nil) - { - return newList; - } - - for (NSUInteger i = 0; i < itemCount; i++) - { - [newList addObject:[[[CocoaDSCheatItem alloc] initWithCheatData:cheatItemArray + i] autorelease]]; - } - - return newList; -} - @end @implementation CocoaDSCheatSearch diff --git a/desmume/src/frontend/cocoa/cocoa_core.mm b/desmume/src/frontend/cocoa/cocoa_core.mm index 50fd06779..5971a1449 100644 --- a/desmume/src/frontend/cocoa/cocoa_core.mm +++ b/desmume/src/frontend/cocoa/cocoa_core.mm @@ -170,7 +170,7 @@ volatile bool execute = true; macOS_driver *newDriver = new macOS_driver; newDriver->SetCoreThreadMutexLock(&threadParam.mutexThreadExecute); - newDriver->SetCoreExecuteRWLock(self.rwlockCoreExecute); + newDriver->SetCoreExecuteRWLock(&threadParam.rwlockCoreExecute); newDriver->SetExecutionControl(execControl); driver = newDriver; @@ -1151,6 +1151,7 @@ static void* RunCoreThread(void *arg) CoreThreadParam *param = (CoreThreadParam *)arg; CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore; CocoaDSGPU *cdsGPU = [cdsCore cdsGPU]; + ClientCheatManager *cheatManager = [[cdsCore cdsCheatManager] internalManager]; ClientExecutionControl *execControl = [cdsCore execControl]; ClientInputHandler *inputHandler = execControl->GetClientInputHandler(); NSMutableArray *cdsOutputList = [cdsCore cdsOutputList]; @@ -1229,11 +1230,9 @@ static void* RunCoreThread(void *arg) avCaptureObject = NULL; } - ClientCheatList *cheatList = [[cdsCore cdsCheatManager] clientListData]; - cheatList->ApplyListToEngine(); - // Execute the frame and increment the frame counter. pthread_rwlock_wrlock(¶m->rwlockCoreExecute); + cheatManager->ApplyToMaster(); NDS_exec(); SPU_Emulate_user(); execControl->FetchOutputPostNDSExec(); diff --git a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm index 706ef0cc5..abc53da52 100644 --- a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm +++ b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm @@ -1206,7 +1206,7 @@ void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplay [cheatItem setValue:0]; // UNUSED [cheatItem setEnabled:enabled]; - [[self cdsCheats] add:cheatItem]; + [[self cdsCheats] addExistingItem:cheatItem]; // OpenEmu doesn't currently save cheats per game, so assume that the // cheat list is short and that code strings are unique. This allows diff --git a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm index 842ed69b0..9b11bd416 100644 --- a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm @@ -1936,7 +1936,7 @@ CocoaDSCheatManager *newCheatList = [cdsCore cdsCheatManager]; if (newCheatList != nil) { - [newCheatList loadFromEngine]; + [newCheatList loadFromMaster]; NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content]; diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h index 8199e494a..a7a8bc303 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2012 DeSmuME team + Copyright (C) 2012-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -57,7 +57,6 @@ NSWindow *cheatDatabaseSheet; - NSUInteger untitledCount; NSFont *codeEditorFont; NSMutableDictionary *bindings; @@ -92,7 +91,6 @@ @property (readonly) IBOutlet NSWindow *cheatDatabaseSheet; -@property (assign) NSUInteger untitledCount; @property (assign) NSFont *codeEditorFont; @property (readonly) NSMutableDictionary *bindings; @property (retain) CocoaDSCheatItem *workingCheat; diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm index 997587ce5..53caf472b 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm @@ -50,7 +50,6 @@ @synthesize cheatDatabaseSheet; -@synthesize untitledCount; @synthesize codeEditorFont; @synthesize bindings; @synthesize cdsCheats; @@ -85,7 +84,6 @@ workingCheat = nil; currentView = nil; currentSearchStyleView = nil; - untitledCount = 0; codeEditorFont = [NSFont fontWithName:@"Monaco" size:13.0]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"hasSelection"]; @@ -107,9 +105,9 @@ } - (void)dealloc -{ - self.workingCheat = nil; - self.cdsCheats = nil; +{ + [self setWorkingCheat:nil]; + [self setCdsCheats:nil]; [cdsCheatSearch release]; [bindings release]; @@ -118,38 +116,24 @@ - (IBAction) addToList:(id)sender { - if (self.cdsCheats == nil) + if ([self cdsCheats] == nil) { return; } - NSString *untitledString = nil; - - self.untitledCount++; - if (self.untitledCount > 1) + CocoaDSCheatItem *newCheatItem = [[[self cdsCheats] newItem] autorelease]; + if (newCheatItem != nil) { - untitledString = [NSString stringWithFormat:@"Untitled %ld", (unsigned long)self.untitledCount]; + [cheatListController addObject:newCheatItem]; + [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasItems"]; + [[self cdsCheats] save]; } - else - { - untitledString = @"Untitled"; - } - - CocoaDSCheatItem *newCheatItem = [[[CocoaDSCheatItem alloc] init] autorelease]; - newCheatItem.cheatType = CHEAT_TYPE_INTERNAL; - newCheatItem.description = untitledString; - - [cheatListController addObject:newCheatItem]; - [self.cdsCheats add:newCheatItem]; - [self.cdsCheats save]; - - [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasItems"]; } - (IBAction) removeFromList:(id)sender { NSMutableArray *cheatList = (NSMutableArray *)[cheatListController content]; - if (cdsCheats == nil || cheatList == nil) + if ( ([self cdsCheats] == nil) || (cheatList == nil) ) { return; } @@ -164,10 +148,10 @@ NSArray *selectedObjects = [cheatListController selectedObjects]; CocoaDSCheatItem *selectedCheat = (CocoaDSCheatItem *)[selectedObjects objectAtIndex:0]; - [self.cdsCheats remove:selectedCheat]; + [[self cdsCheats] remove:selectedCheat]; [cheatListController removeObject:selectedCheat]; - [self.cdsCheats save]; + [[self cdsCheats] save]; [cheatListTable deselectAll:sender]; NSUInteger cheatCount = [cheatList count]; @@ -213,12 +197,12 @@ // Force end of editing of any text fields. [window makeFirstResponder:nil]; - [self.cdsCheats applyInternalCheat:self.workingCheat]; + [[self cdsCheats] applyInternalCheat:[self workingCheat]]; } - (IBAction) applyConfiguration:(id)sender { - if (self.workingCheat == nil) + if ([self workingCheat] == nil) { return; } @@ -226,17 +210,8 @@ // Force end of editing of any text fields. [window makeFirstResponder:nil]; - [self.workingCheat mergeToParent]; - - BOOL result = [self.cdsCheats update:self.workingCheat.parent]; - if (result) - { - [self.cdsCheats save]; - } - else - { - // TODO: Display an error sheet saying that the cheat applying failed. - } + [[self workingCheat] mergeToParent]; + [[self cdsCheats] save]; } - (IBAction) selectCheatType:(id)sender @@ -253,13 +228,13 @@ - (IBAction) selectCheatSearchStyle:(id)sender { NSInteger searchStyle = [CocoaDSUtil getIBActionSenderTag:sender]; - [self.bindings setValue:[NSNumber numberWithInteger:searchStyle] forKey:@"cheatSearchStyle"]; + [bindings setValue:[NSNumber numberWithInteger:searchStyle] forKey:@"cheatSearchStyle"]; [self setCheatSearchViewByStyle:searchStyle]; } - (IBAction) runExactValueSearch:(id)sender { - if (self.workingCheat == nil) + if ([self workingCheat] == nil) { return; } @@ -268,19 +243,18 @@ [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"isRunningSearch"]; NSInteger value = [searchField integerValue]; - UInt8 byteSize = self.workingCheat.bytes; - NSInteger signType = [(NSNumber *)[self.bindings valueForKey:@"cheatSearchSignType"] integerValue]; + UInt8 byteSize = [[self workingCheat] bytes]; + NSInteger signType = [(NSNumber *)[bindings valueForKey:@"cheatSearchSignType"] integerValue]; NSUInteger addressCount = [cdsCheatSearch runExactValueSearch:value byteSize:byteSize signType:signType]; [bindings setValue:[NSNumber numberWithUnsignedInteger:addressCount] forKey:@"cheatSearchAddressCount"]; - [cheatSearchListController setContent:cdsCheatSearch.addressList]; + [cheatSearchListController setContent:[cdsCheatSearch addressList]]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"isRunningSearch"]; - } - (IBAction) runComparativeSearch:(id)sender { - if (self.workingCheat == nil) + if ([self workingCheat] == nil) { return; } @@ -288,28 +262,27 @@ [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"isSearchStarted"]; [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"isRunningSearch"]; - if (cdsCheatSearch.searchCount == 0) + if ([cdsCheatSearch searchCount] == 0) { [bindings setValue:@"Running initial search..." forKey:@"cheatSearchAddressCount"]; [window displayIfNeeded]; } NSInteger compSearchTypeID = [CocoaDSUtil getIBActionSenderTag:sender]; - UInt8 byteSize = self.workingCheat.bytes; - NSInteger signType = [(NSNumber *)[self.bindings valueForKey:@"cheatSearchSignType"] integerValue]; + UInt8 byteSize = [[self workingCheat] bytes]; + NSInteger signType = [(NSNumber *)[bindings valueForKey:@"cheatSearchSignType"] integerValue]; NSUInteger addressCount = [cdsCheatSearch runComparativeSearch:compSearchTypeID byteSize:byteSize signType:signType]; [bindings setValue:[NSNumber numberWithUnsignedInteger:addressCount] forKey:@"cheatSearchAddressCount"]; - [cheatSearchListController setContent:cdsCheatSearch.addressList]; + [cheatSearchListController setContent:[cdsCheatSearch addressList]]; - NSInteger searchStyle = [(NSNumber *)[self.bindings valueForKey:@"cheatSearchStyle"] integerValue]; - if (searchStyle == CHEATSEARCH_SEARCHSTYLE_COMPARATIVE && cdsCheatSearch.searchCount == 1) + NSInteger searchStyle = [(NSNumber *)[bindings valueForKey:@"cheatSearchStyle"] integerValue]; + if (searchStyle == CHEATSEARCH_SEARCHSTYLE_COMPARATIVE && [cdsCheatSearch searchCount] == 1) { [self setCheatSearchViewByStyle:CHEATSEARCH_SEARCHSTYLE_COMPARATIVE]; [bindings setValue:@"Search started!" forKey:@"cheatSearchAddressCount"]; } [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"isRunningSearch"]; - } - (void) searchDidFinish:(NSNotification *)aNotification @@ -319,12 +292,12 @@ if (searcher != nil) { - addressCount = searcher.addressList.count; + addressCount = [[searcher addressList] count]; [bindings setValue:[NSNumber numberWithUnsignedInteger:addressCount] forKey:@"cheatSearchAddressCount"]; - [cheatSearchListController setContent:searcher.addressList]; + [cheatSearchListController setContent:[searcher addressList]]; - NSInteger searchStyle = [(NSNumber *)[self.bindings valueForKey:@"cheatSearchStyle"] integerValue]; - if (searchStyle == CHEATSEARCH_SEARCHSTYLE_COMPARATIVE && searcher.searchCount == 1) + NSInteger searchStyle = [(NSNumber *)[bindings valueForKey:@"cheatSearchStyle"] integerValue]; + if (searchStyle == CHEATSEARCH_SEARCHSTYLE_COMPARATIVE && [searcher searchCount] == 1) { [self setCheatSearchViewByStyle:CHEATSEARCH_SEARCHSTYLE_COMPARATIVE]; [bindings setValue:@"Search started!" forKey:@"cheatSearchAddressCount"]; @@ -338,9 +311,9 @@ { [cheatSearchListController setContent:nil]; [cdsCheatSearch reset]; - [self.bindings setValue:nil forKey:@"cheatSearchSearchValue"]; - [self.bindings setValue:@"Search not started." forKey:@"cheatSearchAddressCount"]; - [self setCheatSearchViewByStyle:[(NSNumber *)[self.bindings valueForKey:@"cheatSearchStyle"] integerValue]]; + [bindings setValue:nil forKey:@"cheatSearchSearchValue"]; + [bindings setValue:@"Search not started." forKey:@"cheatSearchAddressCount"]; + [self setCheatSearchViewByStyle:[(NSNumber *)[bindings valueForKey:@"cheatSearchStyle"] integerValue]]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"isSearchStarted"]; } @@ -397,7 +370,7 @@ break; case CHEATSEARCH_SEARCHSTYLE_COMPARATIVE: - if (cdsCheatSearch.searchCount == 0) + if ([cdsCheatSearch searchCount] == 0) { newView = viewSearchComparativeStart; } @@ -431,7 +404,7 @@ for (CocoaDSCheatItem *cheatItem in dbList) { - cheatItem.willAdd = YES; + [cheatItem setWillAdd:YES]; } } @@ -445,7 +418,7 @@ for (CocoaDSCheatItem *cheatItem in dbList) { - cheatItem.willAdd = NO; + [cheatItem setWillAdd:NO]; } } @@ -457,19 +430,29 @@ return; } - for (CocoaDSCheatItem *cheatItem in dbList) + size_t addedItemCount = 0; + BOOL didAddItem = NO; + + for (CocoaDSCheatItem *dbItem in dbList) { - if (cheatItem.willAdd) + if ([dbItem willAdd]) { - CocoaDSCheatItem *newCheatItem = [[[CocoaDSCheatItem alloc] initWithCocoaCheatItem:cheatItem] autorelease]; - [cheatListController addObject:newCheatItem]; - [self.cdsCheats add:newCheatItem]; + CocoaDSCheatItem *newCocoaCheatItem = [[[CocoaDSCheatItem alloc] init] autorelease]; + ClientCheatItem *newCheatItem = [newCocoaCheatItem clientData]; + newCheatItem->Init(*[dbItem clientData]); + + didAddItem = [[self cdsCheats] addExistingItem:newCocoaCheatItem]; + if (didAddItem) + { + [cheatListController addObject:newCocoaCheatItem]; + addedItemCount++; + } } } - if ([dbList count] > 0) + if (addedItemCount > 0) { - [self.cdsCheats save]; + [[self cdsCheats] save]; [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasItems"]; } } @@ -490,7 +473,6 @@ { case GUI_RESPONSE_CANCEL: return; - break; case GUI_RESPONSE_OK: [self addSelectedFromCheatDatabase]; @@ -503,7 +485,7 @@ - (void)windowDidBecomeKey:(NSNotification *)notification { - [cheatWindowController setContent:self.bindings]; + [cheatWindowController setContent:bindings]; } - (void)tableViewSelectionDidChange:(NSNotification *)aNotification @@ -511,27 +493,27 @@ NSTableView *table = (NSTableView *)[aNotification object]; NSInteger rowIndex = [table selectedRow]; - if (table == self.cheatListTable) + if (table == [self cheatListTable]) { if (rowIndex >= 0) { NSArray *selectedObjects = [cheatListController selectedObjects]; CocoaDSCheatItem *selectedCheat = [selectedObjects objectAtIndex:0]; - self.workingCheat = [selectedCheat createWorkingCopy]; - [cheatSelectedItemController setContent:self.workingCheat]; + [self setWorkingCheat:[selectedCheat createWorkingCopy]]; + [cheatSelectedItemController setContent:[self workingCheat]]; - [self setCheatConfigViewByType:selectedCheat.cheatType]; + [self setCheatConfigViewByType:[selectedCheat cheatType]]; [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasSelection"]; } else { - if (self.workingCheat != nil) + if ([self workingCheat] != nil) { - [self.workingCheat.parent destroyWorkingCopy]; + [[[self workingCheat] parent] destroyWorkingCopy]; } [cheatSelectedItemController setContent:nil]; - self.workingCheat = nil; + [self setWorkingCheat:nil]; NSRect frameRect = [currentView frame]; [currentView retain]; @@ -542,7 +524,7 @@ [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"hasSelection"]; } } - else if (table == self.cheatSearchListTable) + else if (table == [self cheatSearchListTable]) { if (rowIndex >= 0) { @@ -550,9 +532,9 @@ NSMutableDictionary *selectedAddress = [selectedObjects objectAtIndex:0]; NSString *addressString = [(NSString *)[selectedAddress valueForKey:@"addressString"] substringFromIndex:4]; - if (self.workingCheat != nil) + if ([self workingCheat] != nil) { - self.workingCheat.memAddressSixDigitString = addressString; + [[self workingCheat] setMemAddressSixDigitString:addressString]; } } }