1
0
mirror of https://github.com/TASVideos/desmume synced 2024-07-08 20:06:04 +00:00

Cocoa Port: Continue refactoring the cheat system code.

- Add new ClientCheatList C++ class, further reducing dependence on Objective-C code.
- Making any changes to the cheat list or to any cheat items no longer requires the acquisition of an R/W lock.
This commit is contained in:
rogerman 2023-06-30 20:04:19 -07:00
parent 4e7926eaa1
commit 946f7df9bc
9 changed files with 485 additions and 353 deletions

View File

@ -17,6 +17,7 @@
*/
#include <string>
#include <vector>
#import <Cocoa/Cocoa.h>
#undef BOOL
@ -40,18 +41,17 @@ enum CheatFreezeType
enum CheatSystemError
{
CheatSystemError_NoError = 0,
CheatSystemError_FileOpenFailed = 1,
CheatSystemError_NoError = 0,
CheatSystemError_FileOpenFailed = 1,
CheatSystemError_FileFormatInvalid = 2,
CheatSystemError_CheatNotFound = 3,
CheatSystemError_ExportError = 4
CheatSystemError_CheatNotFound = 3,
CheatSystemError_ExportError = 4,
CheatSystemError_FileSaveFailed = 5
};
class ClientCheatItem
{
protected:
CHEATS_LIST *_engineItemPtr;
bool _isEnabled;
bool _willAddFromDB;
@ -81,9 +81,6 @@ public:
void Init(const CHEATS_LIST &inCheatItem);
void Init(const ClientCheatItem &inCheatItem);
void SetEngineItemPtr(CHEATS_LIST *cheatItemPtr);
CHEATS_LIST* GetEngineItemPtr() const;
void SetEnabled(bool theState);
bool IsEnabled() const;
@ -119,6 +116,40 @@ public:
void ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const;
};
class ClientCheatList
{
protected:
std::vector<ClientCheatItem *> *_list;
bool _engineNeedsUpdate;
public:
ClientCheatList();
~ClientCheatList();
CheatSystemError LoadFromFile(const char *filePath);
CheatSystemError SaveToFile(const char *filePath);
ClientCheatItem* AddNew();
ClientCheatItem* Add(ClientCheatItem *srcItem);
ClientCheatItem* AddNoDuplicate(ClientCheatItem *srcItem);
void Remove(ClientCheatItem *targetItem);
void RemoveAtIndex(size_t index);
void RemoveAll();
void Update(const ClientCheatItem &srcItem, ClientCheatItem *targetItem);
ClientCheatItem* UpdateAtIndex(const ClientCheatItem &srcItem, size_t index);
size_t GetTotalCheatCount() const;
size_t GetActiveCheatCount() const;
std::vector<ClientCheatItem *>* GetCheatList() 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
@ -141,7 +172,7 @@ public:
BOOL _isMemAddressAlreadyUpdating;
}
@property (assign, nonatomic) CHEATS_LIST *data;
@property (readonly, nonatomic, getter=clientData) ClientCheatItem *_internalData;
@property (assign) BOOL willAdd;
@property (assign, nonatomic) BOOL enabled;
@property (assign, nonatomic) NSInteger cheatType;
@ -159,8 +190,9 @@ public:
@property (readonly) CocoaDSCheatItem *workingCopy;
@property (assign) CocoaDSCheatItem *parent;
- (id) initWithCheatItem:(CocoaDSCheatItem *)cdsCheatItem;
- (id) initWithCheatData:(CHEATS_LIST *)cheatData;
- (id) initWithCheatItem:(ClientCheatItem *)cheatItem;
- (id) initWithCocoaCheatItem:(CocoaDSCheatItem *)cdsCheatItem;
- (id) initWithCheatData:(const CHEATS_LIST *)cheatData;
- (char *) descriptionCString;
- (void) update;
- (CocoaDSCheatItem *) createWorkingCopy;
@ -186,27 +218,23 @@ public:
********************************************************************************************/
@interface CocoaDSCheatManager : NSObject
{
CHEATS *listData;
ClientCheatList *_clientListData;
NSMutableArray *list;
pthread_rwlock_t *rwlockCoreExecute;
BOOL isUsingDummyRWlock;
NSUInteger untitledCount;
NSString *dbTitle;
NSString *dbDate;
NSURL *lastFileURL;
}
@property (readonly) CHEATS *listData;
@property (readonly, nonatomic, getter=clientListData) ClientCheatList *_clientListData;
@property (readonly) NSMutableArray *list;
@property (assign) pthread_rwlock_t *rwlockCoreExecute;
@property (assign) NSUInteger untitledCount;
@property (copy) NSString *dbTitle;
@property (copy) NSString *dbDate;
@property (retain) NSURL *lastFileURL;
- (id) initWithFileURL:(NSURL *)fileURL;
- (id) initWithListData:(CHEATS *)cheatList;
- (id) initWithFileURL:(NSURL *)fileURL listData:(CHEATS *)cheatList;
- (BOOL) add:(CocoaDSCheatItem *)cheatItem;
- (void) remove:(CocoaDSCheatItem *)cheatItem;
@ -215,11 +243,13 @@ public:
- (NSUInteger) activeCount;
- (NSMutableArray *) cheatListFromDatabase:(NSURL *)fileURL errorCode:(NSInteger *)error;
- (void) applyInternalCheat:(CocoaDSCheatItem *)cheatItem;
- (void) loadFromEngine;
- (void) applyListToEngine;
+ (void) setMasterCheatList:(CocoaDSCheatManager *)cheatListManager;
+ (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

View File

@ -124,8 +124,6 @@ size_t CheatConvertCleanCodeToRawCode(const char *inCleanCodeString, std::string
ClientCheatItem::ClientCheatItem()
{
_engineItemPtr = NULL;
_isEnabled = false;
_willAddFromDB = false;
@ -190,40 +188,26 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem)
void ClientCheatItem::Init(const ClientCheatItem &inCheatItem)
{
this->_isEnabled = inCheatItem.IsEnabled();
this->SetEnabled(inCheatItem.IsEnabled());
this->SetDescription(inCheatItem.GetDescription());
this->SetType(inCheatItem.GetType());
this->SetFreezeType(inCheatItem.GetFreezeType());
this->_cheatType = inCheatItem.GetType();
this->_descriptionString = inCheatItem.GetDescription();
this->_freezeType = inCheatItem.GetFreezeType();
this->_valueLength = inCheatItem.GetValueLength();
this->_address = inCheatItem.GetAddress();
strncpy(this->_addressString, inCheatItem.GetAddressString(), sizeof(this->_addressString));
this->_value = inCheatItem.GetValue();
this->_codeCount = inCheatItem.GetCodeCount();
this->_rawCodeString = inCheatItem.GetRawCodeString();
this->_cleanCodeString = inCheatItem.GetCleanCodeString();
}
void ClientCheatItem::SetEngineItemPtr(CHEATS_LIST *cheatItemPtr)
{
this->_engineItemPtr = cheatItemPtr;
}
CHEATS_LIST* ClientCheatItem::GetEngineItemPtr() const
{
return this->_engineItemPtr;
if (this->GetType() == CheatType_Internal)
{
this->SetValueLength(inCheatItem.GetValueLength());
this->SetAddress(inCheatItem.GetAddress());
this->SetValue(inCheatItem.GetValue());
}
else
{
this->SetRawCodeString(inCheatItem.GetRawCodeString(), false);
}
}
void ClientCheatItem::SetEnabled(bool theState)
{
this->_isEnabled = theState;
if (this->_engineItemPtr != NULL)
{
this->_engineItemPtr->enabled = (theState) ? 1 : 0;
}
}
bool ClientCheatItem::IsEnabled() const
@ -262,11 +246,6 @@ void ClientCheatItem::SetType(CheatType requestedType)
}
this->_cheatType = requestedType;
if (this->_engineItemPtr != NULL)
{
this->_engineItemPtr->type = (u8)requestedType;
}
}
bool ClientCheatItem::IsSupportedType() const
@ -289,11 +268,6 @@ void ClientCheatItem::SetDescription(const char *descriptionString)
{
this->_descriptionString = descriptionString;
}
if (this->_engineItemPtr != NULL)
{
strncpy(this->_engineItemPtr->description, this->_descriptionString.c_str(), sizeof(this->_engineItemPtr->description));
}
}
CheatFreezeType ClientCheatItem::GetFreezeType() const
@ -317,11 +291,6 @@ void ClientCheatItem::SetFreezeType(CheatFreezeType theFreezeType)
}
this->_freezeType = theFreezeType;
if (this->_engineItemPtr != NULL)
{
this->_engineItemPtr->freezeType = (u8)theFreezeType;
}
}
uint32_t ClientCheatItem::GetAddress() const
@ -347,11 +316,6 @@ void ClientCheatItem::SetAddress(uint32_t theAddress)
{
this->_ConvertInternalToActionReplay();
}
if ( (this->_engineItemPtr != NULL) && (this->_cheatType == CheatType_Internal) )
{
this->_engineItemPtr->code[0][0] = theAddress;
}
}
const char* ClientCheatItem::GetAddressString() const
@ -397,11 +361,6 @@ void ClientCheatItem::SetAddressSixDigitString(const char *sixDigitString)
{
this->_ConvertInternalToActionReplay();
}
if ( (this->_engineItemPtr != NULL) && (this->_cheatType == CheatType_Internal) )
{
this->_engineItemPtr->code[0][0] = this->_address;
}
}
uint32_t ClientCheatItem::GetValue() const
@ -417,11 +376,6 @@ void ClientCheatItem::SetValue(uint32_t theValue)
{
this->_ConvertInternalToActionReplay();
}
if ( (this->_engineItemPtr != NULL) && (this->_cheatType == CheatType_Internal) )
{
this->_engineItemPtr->code[0][1] = (u32)theValue;
}
}
uint8_t ClientCheatItem::GetValueLength() const
@ -437,11 +391,6 @@ void ClientCheatItem::SetValueLength(uint8_t byteLength)
{
this->_ConvertInternalToActionReplay();
}
if ( (this->_engineItemPtr != NULL) && (this->_cheatType == CheatType_Internal) )
{
this->_engineItemPtr->size = (u8)(byteLength - 1); // CHEATS_LIST.size value range is [1...4], but starts counting from 0.
}
}
void ClientCheatItem::SetRawCodeString(const char *rawString, const bool willSaveValidatedRawString)
@ -474,11 +423,6 @@ void ClientCheatItem::SetRawCodeString(const char *rawString, const bool willSav
{
this->_ConvertActionReplayToInternal();
}
if (this->_engineItemPtr != NULL)
{
CHEATS::XXCodeFromString(this->_cleanCodeString.c_str(), *this->_engineItemPtr);
}
}
const char* ClientCheatItem::GetRawCodeString() const
@ -575,10 +519,17 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const
outCheatItem->size = 3;
outCheatItem->freezeType = CheatFreezeType_Normal;
char valueString[9];
valueString[8] = '\0';
const char *cleanCodeStr = this->_cleanCodeString.c_str();
for (size_t i = 0; i < this->_codeCount; i++)
{
sscanf(this->_cleanCodeString.c_str() + (i * 16) + 0, "%x", &outCheatItem->code[i][0]);
sscanf(this->_cleanCodeString.c_str() + (i * 16) + 8, "%x", &outCheatItem->code[i][1]);
strncpy(valueString, cleanCodeStr + (i * 16) + 0, 8);
sscanf(valueString, "%x", &outCheatItem->code[i][0]);
strncpy(valueString, cleanCodeStr + (i * 16) + 8, 8);
sscanf(valueString, "%x", &outCheatItem->code[i][1]);
}
break;
}
@ -590,13 +541,310 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const
#pragma mark -
ClientCheatList::ClientCheatList()
{
_list = new std::vector<ClientCheatItem *>;
_engineNeedsUpdate = true;
}
ClientCheatList::~ClientCheatList()
{
delete this->_list;
this->_list = NULL;
}
CheatSystemError ClientCheatList::LoadFromFile(const char *filePath)
{
CheatSystemError error = CheatSystemError_NoError;
if (filePath == NULL)
{
error = CheatSystemError_FileOpenFailed;
return error;
}
CHEATS *tempEngineList = new CHEATS;
tempEngineList->init((char *)filePath);
this->ReplaceFromEngine(tempEngineList);
delete tempEngineList;
return error;
}
CheatSystemError ClientCheatList::SaveToFile(const char *filePath)
{
CheatSystemError error = CheatSystemError_NoError;
if (filePath == NULL)
{
error = CheatSystemError_FileOpenFailed;
return error;
}
CHEATS *tempEngineList = new CHEATS;
tempEngineList->setFilePath(filePath);
this->CopyListToEngine(false, tempEngineList);
bool isSaveSuccessful = tempEngineList->save();
if (!isSaveSuccessful)
{
error = CheatSystemError_FileSaveFailed;
}
delete tempEngineList;
return error;
}
ClientCheatItem* ClientCheatList::AddNew()
{
this->_list->push_back(new ClientCheatItem);
return this->_list->back();
}
ClientCheatItem* ClientCheatList::Add(ClientCheatItem *srcItem)
{
if (srcItem == NULL)
{
return NULL;
}
ClientCheatItem *newItem = this->AddNew();
newItem->Init(*srcItem);
if (newItem->IsEnabled())
{
this->_engineNeedsUpdate = true;
}
return newItem;
}
ClientCheatItem* ClientCheatList::AddNoDuplicate(ClientCheatItem *srcItem)
{
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;
}
void ClientCheatList::Remove(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->RemoveAtIndex(i);
break;
}
}
}
void ClientCheatList::RemoveAtIndex(size_t index)
{
if (index >= this->_list->size())
{
return;
}
ClientCheatItem *itemToRemove = (*this->_list)[index];
if (itemToRemove->IsEnabled())
{
this->_engineNeedsUpdate = true;
}
this->_list->erase( this->_list->begin() + index );
delete itemToRemove;
}
void ClientCheatList::RemoveAll()
{
const size_t cheatCount = this->_list->size();
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)
{
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;
}
}
}
ClientCheatItem* ClientCheatList::UpdateAtIndex(const ClientCheatItem &srcItem, size_t index)
{
ClientCheatItem *targetItem = this->GetItemAtIndex(index);
if (targetItem != NULL)
{
targetItem->Init(srcItem);
if (targetItem->IsEnabled())
{
this->_engineNeedsUpdate = true;
}
}
return targetItem;
}
size_t ClientCheatList::GetTotalCheatCount() const
{
return this->_list->size();
}
size_t ClientCheatList::GetActiveCheatCount() const
{
size_t activeCount = 0;
const size_t totalCount = this->_list->size();
for (size_t i = 0; i < totalCount; i++)
{
ClientCheatItem *cheatItem = (*this->_list)[i];
if (cheatItem->IsEnabled())
{
activeCount++;
}
}
return activeCount;
}
std::vector<ClientCheatItem *>* ClientCheatList::GetCheatList() const
{
return this->_list;
}
ClientCheatItem* ClientCheatList::GetItemAtIndex(size_t index) const
{
if (index >= this->GetTotalCheatCount())
{
return NULL;
}
return (*this->_list)[index];
}
void ClientCheatList::ReplaceFromEngine(const CHEATS *engineCheatList)
{
if (engineCheatList == NULL)
{
return;
}
this->RemoveAll();
const size_t totalCount = engineCheatList->getListSize();
for (size_t i = 0; i < totalCount; i++)
{
ClientCheatItem *newItem = this->AddNew();
newItem->Init( *engineCheatList->getItemPtrAtIndex(i) );
if (newItem->IsEnabled())
{
this->_engineNeedsUpdate = true;
}
}
}
void ClientCheatList::CopyListToEngine(const bool willApplyOnlyEnabledItems, CHEATS *engineCheatList)
{
if (engineCheatList == NULL)
{
return;
}
CHEATS_LIST tempEngineItem;
engineCheatList->clear();
const size_t totalCount = this->_list->size();
for (size_t i = 0; i < totalCount; i++)
{
ClientCheatItem *cheatItem = (*this->_list)[i];
if (cheatItem->IsEnabled() || !willApplyOnlyEnabledItems)
{
cheatItem->ClientToDesmumeCheatItem(&tempEngineItem);
engineCheatList->addItem(tempEngineItem);
}
}
}
void ClientCheatList::ApplyListToEngine()
{
CHEATS *engineCheatList = ClientCheatList::GetMasterCheatList();
if ( (engineCheatList == NULL) || !this->_engineNeedsUpdate )
{
return;
}
this->CopyListToEngine(true, engineCheatList);
this->_engineNeedsUpdate = false;
}
CHEATS* ClientCheatList::GetMasterCheatList()
{
return cheats;
}
#pragma mark -
@implementation CocoaDSCheatItem
static NSImage *iconInternalCheat = nil;
static NSImage *iconActionReplay = nil;
static NSImage *iconCodeBreaker = nil;
@dynamic data;
@synthesize _internalData;
@synthesize willAdd;
@dynamic enabled;
@dynamic cheatType;
@ -619,7 +867,7 @@ static NSImage *iconCodeBreaker = nil;
return [self initWithCheatData:nil];
}
- (id) initWithCheatItem:(CocoaDSCheatItem *)cdsCheatItem
- (id) initWithCheatItem:(ClientCheatItem *)cheatItem
{
self = [super init];
if(self == nil)
@ -634,29 +882,25 @@ static NSImage *iconCodeBreaker = nil;
parent = nil;
_isMemAddressAlreadyUpdating = NO;
if (cdsCheatItem != nil)
if (cheatItem != NULL)
{
_internalData->SetEnabled(([cdsCheatItem enabled]) ? true : false);
_internalData->SetDescription([[cdsCheatItem description] cStringUsingEncoding:NSUTF8StringEncoding]);
_internalData->SetType((CheatType)[cdsCheatItem cheatType]);
_internalData->SetFreezeType((CheatFreezeType)[cdsCheatItem freezeType]);
if (_internalData->GetType() == CheatType_Internal)
{
_internalData->SetValueLength([cdsCheatItem bytes]);
_internalData->SetAddress([cdsCheatItem memAddress]);
_internalData->SetValue((u32)[cdsCheatItem value]);
}
else
{
_internalData->SetRawCodeString([[cdsCheatItem code] cStringUsingEncoding:NSUTF8StringEncoding], false);
}
_internalData->Init(*cheatItem);
}
return self;
}
- (id) initWithCheatData:(CHEATS_LIST *)cheatData
- (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];
if(self == nil)
@ -668,7 +912,6 @@ static NSImage *iconCodeBreaker = nil;
if (cheatData != NULL)
{
_internalData->SetEngineItemPtr(cheatData);
_internalData->Init(*cheatData);
}
@ -690,16 +933,6 @@ static NSImage *iconCodeBreaker = nil;
[super dealloc];
}
- (CHEATS_LIST *) data
{
return _internalData->GetEngineItemPtr();
}
- (void) setData:(CHEATS_LIST *)cheatData
{
_internalData->SetEngineItemPtr(cheatData);
}
- (BOOL) enabled
{
return _internalData->IsEnabled() ? YES : NO;
@ -1011,7 +1244,7 @@ static NSImage *iconCodeBreaker = nil;
[workingCopy release];
}
newWorkingCopy = [[CocoaDSCheatItem alloc] initWithCheatItem:self];
newWorkingCopy = [[CocoaDSCheatItem alloc] initWithCocoaCheatItem:self];
[newWorkingCopy setParent:self];
workingCopy = newWorkingCopy;
@ -1069,29 +1302,19 @@ static NSImage *iconCodeBreaker = nil;
@implementation CocoaDSCheatManager
@synthesize listData;
@synthesize _clientListData;
@synthesize list;
@dynamic rwlockCoreExecute;
@synthesize untitledCount;
@synthesize dbTitle;
@synthesize dbDate;
@synthesize lastFileURL;
- (id)init
{
return [self initWithFileURL:nil listData:nil];
return [self initWithFileURL:nil];
}
- (id) initWithFileURL:(NSURL *)fileURL
{
return [self initWithFileURL:fileURL listData:nil];
}
- (id) initWithListData:(CHEATS *)cheatList
{
return [self initWithFileURL:nil listData:cheatList];
}
- (id) initWithFileURL:(NSURL *)fileURL listData:(CHEATS *)cheatList
{
self = [super init];
if(self == nil)
@ -1099,42 +1322,25 @@ static NSImage *iconCodeBreaker = nil;
return self;
}
if (cheatList == nil)
{
CHEATS *newListData = new CHEATS();
if (newListData == nil)
{
[self release];
return nil;
}
listData = newListData;
}
else
{
listData = cheatList;
}
_clientListData = new ClientCheatList;
if (fileURL != nil)
{
listData->init((char *)[CocoaDSUtil cPathFromFileURL:fileURL]);
list = [[CocoaDSCheatManager cheatListWithListObject:listData] retain];
lastFileURL = [fileURL copy];
_clientListData->LoadFromFile([CocoaDSUtil cPathFromFileURL:lastFileURL]);
list = [[CocoaDSCheatManager cheatListWithClientListObject:_clientListData] retain];
}
else
{
list = [[NSMutableArray alloc] initWithCapacity:100];
if (list == nil)
{
delete listData;
delete _clientListData;
[self release];
return nil;
}
}
rwlockCoreExecute = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t));
pthread_rwlock_init(rwlockCoreExecute, NULL);
isUsingDummyRWlock = YES;
untitledCount = 0;
dbTitle = nil;
dbDate = nil;
@ -1146,51 +1352,18 @@ static NSImage *iconCodeBreaker = nil;
{
[self setDbTitle:nil];
[self setDbDate:nil];
[list release];
delete (CHEATS *)[self listData];
cheats = NULL;
if (isUsingDummyRWlock)
{
pthread_rwlock_destroy(rwlockCoreExecute);
free(rwlockCoreExecute);
rwlockCoreExecute = NULL;
}
[list release];
list = nil;
[self setLastFileURL:nil];
delete _clientListData;
_clientListData = NULL;
[super dealloc];
}
- (void) setRwlockCoreExecute:(pthread_rwlock_t *)theRwlock
{
if (theRwlock == NULL && isUsingDummyRWlock)
{
return;
}
else if (theRwlock == NULL && !isUsingDummyRWlock)
{
rwlockCoreExecute = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t));
pthread_rwlock_init(rwlockCoreExecute, NULL);
isUsingDummyRWlock = YES;
return;
}
else if (theRwlock != NULL && isUsingDummyRWlock)
{
pthread_rwlock_destroy(rwlockCoreExecute);
free(rwlockCoreExecute);
isUsingDummyRWlock = NO;
rwlockCoreExecute = theRwlock;
}
else if (theRwlock != NULL && !isUsingDummyRWlock)
{
rwlockCoreExecute = theRwlock;
}
}
- (pthread_rwlock_t *) rwlockCoreExecute
{
return rwlockCoreExecute;
}
- (BOOL) add:(CocoaDSCheatItem *)cheatItem
{
BOOL result = NO;
@ -1200,67 +1373,13 @@ static NSImage *iconCodeBreaker = nil;
return result;
}
// Get the current pointer to the raw cheat list data. We will need it later
// to check if the list got reallocated.
CHEATS_LIST *cheatListData = [self listData]->getListPtr();
pthread_rwlock_wrlock([self rwlockCoreExecute]);
const bool cheatItemEnabled = ([cheatItem enabled]) ? true : false;
switch ([cheatItem cheatType])
{
case CHEAT_TYPE_INTERNAL:
result = [self listData]->add([cheatItem bytes] - 1, [cheatItem memAddress], (u32)[cheatItem value], [cheatItem descriptionCString], cheatItemEnabled);
break;
case CHEAT_TYPE_ACTION_REPLAY:
{
char *cheatCodes = (char *)[[cheatItem code] cStringUsingEncoding:NSUTF8StringEncoding];
if (cheatCodes != nil)
{
result = [self listData]->add_AR(cheatCodes, [cheatItem descriptionCString], cheatItemEnabled);
}
break;
}
case CHEAT_TYPE_CODE_BREAKER:
{
char *cheatCodes = (char *)[[cheatItem code] cStringUsingEncoding:NSUTF8StringEncoding];
if (cheatCodes != nil)
{
result = [self listData]->add_CB(cheatCodes, [cheatItem descriptionCString], cheatItemEnabled);
}
break;
}
default:
break;
}
pthread_rwlock_unlock([self rwlockCoreExecute]);
_clientListData->Add([cheatItem clientData]);
if (![[self list] containsObject:cheatItem])
{
[[self list] addObject:cheatItem];
}
// Adding a new item may cause the raw list data to get reallocated, which
// will break the data pointers. So check for reallocation, and if it occurs,
// reset the data pointers for each item.
if (cheatListData != [self listData]->getListPtr())
{
NSUInteger listCount = [self listData]->getListSize();
for (NSUInteger i = 0; i < listCount; i++)
{
CocoaDSCheatItem *itemInList = (CocoaDSCheatItem *)[[self list] objectAtIndex:i];
[itemInList setData:[self listData]->getItemPtrAtIndex(i)];
}
}
else
{
[cheatItem setData:[self listData]->getItemPtrAtIndex([self listData]->getListSize() - 1)];
}
return result;
}
@ -1277,17 +1396,7 @@ static NSImage *iconCodeBreaker = nil;
return;
}
pthread_rwlock_wrlock([self rwlockCoreExecute]);
[self listData]->remove(selectionIndex);
pthread_rwlock_unlock([self rwlockCoreExecute]);
// Removing an item from the raw cheat list data shifts all higher elements
// by one, so we need to do the same.
NSUInteger listCount = [self listData]->getListSize();
for (NSUInteger i = selectionIndex; i < listCount; i++)
{
[(CocoaDSCheatItem *)[[self list] objectAtIndex:(i + 1)] setData:[self listData]->getItemPtrAtIndex(i)];
}
_clientListData->RemoveAtIndex(selectionIndex);
[[self list] removeObject:cheatItem];
}
@ -1307,62 +1416,22 @@ static NSImage *iconCodeBreaker = nil;
return result;
}
pthread_rwlock_wrlock([self rwlockCoreExecute]);
const bool cheatItemEnabled = ([cheatItem enabled]) ? true : false;
switch ([cheatItem cheatType])
{
case CHEAT_TYPE_INTERNAL:
result = [self listData]->update([cheatItem bytes] - 1, [cheatItem memAddress], (u32)[cheatItem value], [cheatItem descriptionCString], cheatItemEnabled, selectionIndex);
break;
case CHEAT_TYPE_ACTION_REPLAY:
{
char *cheatCodes = (char *)[[cheatItem code] cStringUsingEncoding:NSUTF8StringEncoding];
if (cheatCodes != nil)
{
result = [self listData]->update_AR(cheatCodes, [cheatItem descriptionCString], cheatItemEnabled, selectionIndex);
}
break;
}
case CHEAT_TYPE_CODE_BREAKER:
{
char *cheatCodes = (char *)[[cheatItem code] cStringUsingEncoding:NSUTF8StringEncoding];
if (cheatCodes != nil)
{
result = [self listData]->update_CB(cheatCodes, [cheatItem descriptionCString], cheatItemEnabled, selectionIndex);
}
break;
}
default:
break;
}
pthread_rwlock_unlock([self rwlockCoreExecute]);
_clientListData->UpdateAtIndex(*[cheatItem clientData], selectionIndex);
[cheatItem update];
return result;
}
- (BOOL) save
{
pthread_rwlock_wrlock([self rwlockCoreExecute]);
BOOL result = [self listData]->save();
pthread_rwlock_unlock([self rwlockCoreExecute]);
return result;
const CheatSystemError error = _clientListData->SaveToFile([CocoaDSUtil cPathFromFileURL:[self lastFileURL]]);
return (error == CheatSystemError_NoError) ? YES : NO;
}
- (NSUInteger) activeCount
{
pthread_rwlock_rdlock([self rwlockCoreExecute]);
NSUInteger activeCheatsCount = [self listData]->getActiveCount();
pthread_rwlock_unlock([self rwlockCoreExecute]);
return activeCheatsCount;
return (NSUInteger)_clientListData->GetActiveCheatCount();
}
- (NSMutableArray *) cheatListFromDatabase:(NSURL *)fileURL errorCode:(NSInteger *)error
@ -1394,7 +1463,6 @@ static NSImage *iconCodeBreaker = nil;
for (CocoaDSCheatItem *cheatItem in newDBList)
{
[cheatItem setWillAdd:NO];
[cheatItem setData:NULL];
}
}
}
@ -1406,24 +1474,40 @@ static NSImage *iconCodeBreaker = nil;
}
- (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;
}
pthread_rwlock_wrlock([self rwlockCoreExecute]);
[CocoaDSCheatManager applyInternalCheatWithItem:cheatItem];
pthread_rwlock_unlock([self rwlockCoreExecute]);
}
+ (void) setMasterCheatList:(CocoaDSCheatManager *)cheatListManager
{
cheats = [cheatListManager listData];
}
+ (void) applyInternalCheatWithItem:(CocoaDSCheatItem *)cheatItem
{
[CocoaDSCheatManager applyInternalCheatWithAddress:[cheatItem memAddress] value:(u32)[cheatItem value] bytes:[cheatItem bytes]];
}
@ -1493,6 +1577,33 @@ static NSImage *iconCodeBreaker = nil;
return newList;
}
+ (NSMutableArray *) cheatListWithClientListObject:(ClientCheatList *)cheatList
{
if (cheatList == nil)
{
return nil;
}
NSMutableArray *newList = [NSMutableArray arrayWithCapacity:100];
if (newList == nil)
{
return newList;
}
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)
{
[newList addObject:[newItem autorelease]];
}
}
return newList;
}
+ (NSMutableArray *) cheatListWithItemStructArray:(CHEATS_LIST *)cheatItemArray count:(NSUInteger)itemCount
{
if (cheatItemArray == nil)

View File

@ -31,6 +31,7 @@ class ClientExecutionControl;
@class CocoaDSFirmware;
@class CocoaDSGPU;
@class CocoaDSOutput;
@class CocoaDSCheatManager;
typedef struct
{
@ -48,6 +49,7 @@ typedef struct
CocoaDSController *cdsController;
CocoaDSFirmware *cdsFirmware;
CocoaDSGPU *cdsGPU;
CocoaDSCheatManager *cdsCheatManager;
NSMutableArray *cdsOutputList;
pthread_t coreThread;
@ -72,6 +74,7 @@ typedef struct
@property (retain) CocoaDSFirmware *cdsFirmware;
@property (readonly) CocoaDSController *cdsController;
@property (readonly) CocoaDSGPU *cdsGPU;
@property (readonly) CocoaDSCheatManager *cdsCheatManager;
@property (readonly) NSMutableArray *cdsOutputList;
@property (assign) BOOL masterExecute;

View File

@ -20,6 +20,7 @@
#import "cocoa_input.h"
#import "cocoa_firmware.h"
#import "cocoa_GPU.h"
#import "cocoa_cheat.h"
#import "cocoa_globals.h"
#import "cocoa_output.h"
#import "cocoa_rom.h"
@ -48,6 +49,7 @@ volatile bool execute = true;
@synthesize cdsFirmware;
@synthesize cdsController;
@synthesize cdsGPU;
@synthesize cdsCheatManager;
@synthesize cdsOutputList;
@dynamic masterExecute;
@ -122,6 +124,7 @@ volatile bool execute = true;
cdsFirmware = nil;
cdsController = [[CocoaDSController alloc] init];
cdsGPU = [[CocoaDSGPU alloc] init];
cdsCheatManager = [[CocoaDSCheatManager alloc] init];
cdsOutputList = [[NSMutableArray alloc] initWithCapacity:32];
ClientInputHandler *inputHandler = [cdsController inputHandler];
@ -1226,6 +1229,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(&param->rwlockCoreExecute);
NDS_exec<false>();

View File

@ -195,7 +195,6 @@ volatile bool execute = true;
// Set up the cheat system
cdsCheats = [[CocoaDSCheatManager alloc] init];
[cdsCheats setRwlockCoreExecute:&rwlockCoreExecute];
addedCheatsDict = [[NSMutableDictionary alloc] initWithCapacity:128];
// Set up the DS firmware using the internal firmware
@ -719,8 +718,6 @@ void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplay
isRomLoaded = [CocoaDSFile loadRom:[NSURL fileURLWithPath:path]];
[CocoaDSCheatManager setMasterCheatList:cdsCheats];
// Set the default options.
// Have to do it now because displayModeInfo is only available now -- not at this object's init.
NSDictionary<NSString *, id> *userDefaultsDisplayMode = nil;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2013-2022 DeSmuME Team
Copyright (C) 2013-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
@ -42,8 +42,6 @@ class AudioSampleBlockGenerator;
CocoaDSRom *currentRom;
CocoaDSFirmware *cdsFirmware;
CocoaDSSpeaker *cdsSpeaker;
CocoaDSCheatManager *cdsCheats;
CocoaDSCheatManager *dummyCheatList;
CheatWindowDelegate *cheatWindowDelegate;
MacScreenshotCaptureToolDelegate *screenshotCaptureToolDelegate;
@ -138,7 +136,6 @@ class AudioSampleBlockGenerator;
@property (assign) CocoaDSRom *currentRom; // Don't rely on autorelease since the emulator doesn't support concurrent unloading
@property (retain) CocoaDSFirmware *cdsFirmware;
@property (retain) CocoaDSSpeaker *cdsSpeaker;
@property (retain) CocoaDSCheatManager *cdsCheats;
@property (readonly) IBOutlet CheatWindowDelegate *cheatWindowDelegate;
@property (readonly) IBOutlet MacScreenshotCaptureToolDelegate *screenshotCaptureToolDelegate;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2013-2022 DeSmuME Team
Copyright (C) 2013-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
@ -46,7 +46,6 @@
@synthesize currentRom;
@dynamic cdsFirmware;
@dynamic cdsSpeaker;
@synthesize cdsCheats;
@synthesize cheatWindowDelegate;
@synthesize screenshotCaptureToolDelegate;
@ -134,7 +133,6 @@
currentRom = nil;
cdsFirmware = nil;
cdsSpeaker = nil;
dummyCheatList = nil;
isSaveStateEdited = NO;
isShowingSaveStateDialog = NO;
@ -231,7 +229,6 @@
[[self currentRom] release];
[self setCurrentRom:nil];
[self setCdsCheats:nil];
[self setCdsSpeaker:nil];
[self setIsWorking:NO];
@ -1935,16 +1932,15 @@
[romInfoPanelController setContent:[theRom bindings]];
// If the ROM has an associated cheat file, load it now.
NSString *cheatsPath = [[CocoaDSFile fileURLFromRomURL:[theRom fileURL] toKind:@"Cheat"] path];
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
CocoaDSCheatManager *newCheatList = [[[CocoaDSCheatManager alloc] initWithFileURL:[NSURL fileURLWithPath:cheatsPath]] autorelease];
CocoaDSCheatManager *newCheatList = [cdsCore cdsCheatManager];
if (newCheatList != nil)
{
[newCheatList loadFromEngine];
NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content];
[CocoaDSCheatManager setMasterCheatList:newCheatList];
[cheatListController setContent:[newCheatList list]];
[self setCdsCheats:newCheatList];
[cheatWindowBindings setValue:newCheatList forKey:@"cheatList"];
NSString *filePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"R4Cheat_DatabasePath"];
@ -1952,13 +1948,13 @@
{
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSInteger error = 0;
NSMutableArray *dbList = [[self cdsCheats] cheatListFromDatabase:fileURL errorCode:&error];
NSMutableArray *dbList = [newCheatList cheatListFromDatabase:fileURL errorCode:&error];
if (dbList != nil)
{
[cheatDatabaseController setContent:dbList];
NSString *titleString = [[self cdsCheats] dbTitle];
NSString *dateString = [[self cdsCheats] dbDate];
NSString *titleString = [newCheatList dbTitle];
NSString *dateString = [newCheatList dbDate];
[cheatWindowBindings setValue:titleString forKey:@"cheatDBTitle"];
[cheatWindowBindings setValue:dateString forKey:@"cheatDBDate"];
@ -2058,7 +2054,7 @@
}
// Save the ROM's cheat list before unloading.
[[self cdsCheats] save];
[[cdsCore cdsCheatManager] save];
// Update the UI to indicate that the ROM has started the process of unloading.
[self setStatusText:NSSTRING_STATUS_ROM_UNLOADING];
@ -2083,14 +2079,6 @@
[[self currentRom] release];
[self setCurrentRom:nil];
// Release the current cheat list and assign the empty list.
[self setCdsCheats:nil];
if (dummyCheatList == nil)
{
dummyCheatList = [[CocoaDSCheatManager alloc] init];
}
[CocoaDSCheatManager setMasterCheatList:dummyCheatList];
// Update the UI to indicate that the ROM has finished unloading.
[self updateAllWindowTitles];
[screenshotCaptureToolDelegate setRomName:[currentRom internalName]];

View File

@ -461,7 +461,7 @@
{
if (cheatItem.willAdd)
{
CocoaDSCheatItem *newCheatItem = [[[CocoaDSCheatItem alloc] initWithCheatItem:cheatItem] autorelease];
CocoaDSCheatItem *newCheatItem = [[[CocoaDSCheatItem alloc] initWithCocoaCheatItem:cheatItem] autorelease];
[cheatListController addObject:newCheatItem];
[self.cdsCheats add:newCheatItem];
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2012-2022 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
@ -147,7 +147,7 @@
finalFormTextStr = [[finalFormTextStr stringByAppendingString:@"\nAudio - Sound Interpolation Method: "] stringByAppendingString:[[emuControl cdsSpeaker] spuInterpolationModeString]];
finalFormTextStr = [[finalFormTextStr stringByAppendingString:@"\nAudio - Sound Synchronization Method: "] stringByAppendingString:[[emuControl cdsSpeaker] spuSyncMethodString]];
finalFormTextStr = [finalFormTextStr stringByAppendingString:@"\n"];
finalFormTextStr = [[finalFormTextStr stringByAppendingString:@"\nCheats: "] stringByAppendingString:(([cdsCore isCheatingEnabled] && ([[emuControl cdsCheats] activeCount] > 0)) ? [NSString stringWithFormat:@"YES (ActiveCheatCount=%ld)", (unsigned long)[[emuControl cdsCheats] activeCount]] : @"NO")];
finalFormTextStr = [[finalFormTextStr stringByAppendingString:@"\nCheats: "] stringByAppendingString:(([cdsCore isCheatingEnabled] && ([[cdsCore cdsCheatManager] activeCount] > 0)) ? [NSString stringWithFormat:@"YES (ActiveCheatCount=%ld)", (unsigned long)[[cdsCore cdsCheatManager] activeCount]] : @"NO")];
finalFormTextStr = [finalFormTextStr stringByAppendingString:@"\n"];
if ([window contentView] == viewSupportRequest)