123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- //
- // RedSpineBakeModel.cpp
- // empty2dx-desktop
- //
- // Created by Liang zhong on 2022/11/5.
- //
- #include "RedSpineBakeManage.h"
- #include "RedBakeSpineIO.h"
- #include <fstream>
- const static std::string REDSPINEBAKE_EXTENSION = ".rb";
- static RedSpineBakeManage* single = nullptr;
- RedSpineBakeManage* RedSpineBakeManage::getInstance() {
- if (single == nullptr) {
- single = new RedSpineBakeManage();
- }
- return single;
- }
- void RedSpineBakeManage::destoryInstance() {
- if (single) {
- single->_release();
- delete single;
- single = nullptr;
- }
- }
- void RedSpineBakeManage::setCurrentAnimationBakeModel(std::string aName,RedAnimationBakeModel *aAni){
- if(animateList[fileName][aName]==nullptr){
- animateList[fileName][aName] = aAni;
- }
- }
- RedAnimationBakeModel * RedSpineBakeManage::getAnimateByName(std::string aFileName,std::string aName){
- if(animateList.find(aFileName) != animateList.end()) {
- if (animateList[aFileName].count(aName) > 0) {
- return animateList[aFileName][aName];
- } else {
- const ::google::protobuf::Map<std::string, ::RedSpineBakeProto::DataInfo>& dataIndex_pb = dataIndexPbList[aFileName];
- auto iter = dataIndex_pb.find(aName);
- if (iter == dataIndex_pb.end()) {
- // log("sc test android getAnimationByName 索引失败");
- // CCASSERT(false, "索引失败");
- // return nullptr;
- }
- const RedSpineBakeProto::DataInfo& dataInfo = iter->second;
- ::RedSpineBakeProto::RedAnimationBakeModel model_pb;
-
- const cocos2d::Data& byteData = byteArrayList[aFileName];
-
- ///如果byteArrayList为空 且为低端机 需要重新进行io 读取对应的动作信息
- if(byteData.getBytes() == NULL && !CocosConfig::isCharacterRbCache()){
- bool isOk = false;
- #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
- JniMethodInfo methodInfo;
- jbyteArray byteArray = nullptr;
- if (JniHelper::getStaticMethodInfo(methodInfo, BinaryFileClassName, "loadData", "(Ljava/lang/String;II)[B")) {
- jstring jFileName = methodInfo.env->NewStringUTF((aFileName+REDSPINEBAKE_EXTENSION).c_str());
-
- jbyteArray result = (jbyteArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, jFileName, (int)dataInfo.offset(), (int)dataInfo.length());
-
- byteArray = (jbyteArray)methodInfo.env->NewGlobalRef(result);
- // 释放 Java 字符串
- methodInfo.env->DeleteLocalRef(result);
- methodInfo.env->DeleteLocalRef(methodInfo.classID);
- methodInfo.env->DeleteLocalRef(jFileName);
-
- if (byteArray != nullptr) {
- jbyte* byteData = methodInfo.env->GetByteArrayElements(byteArray, NULL);
- BYTE* byteArr = (BYTE*)byteData;
- isOk = model_pb.ParseFromArray(byteArr, dataInfo.length());
- methodInfo.env->ReleaseByteArrayElements(byteArray, byteData, JNI_ABORT);
- }
- else{
- isOk = false;
- }
- }
- #else
- std::string fileFullPath = FileUtils::getInstance()->fullPathForFilename( aFileName + REDSPINEBAKE_EXTENSION);
- ///重新进行io
- std::ifstream file(fileFullPath, std::ios::binary | std::ios::ate);
-
- if (!file.is_open()) {
- CCASSERT(false, "打开文件失败");
- }
- // log("sc_test getAnimationByName,%s, %d, %d", aName.c_str(), dataInfo.offset(), dataInfo.length());
- // 获取文件大小
- std::streampos fileSize = file.tellg();
- // 将文件指针移动到currentOffset的位置
- file.seekg(dataInfo.offset(), std::ios::beg);
- // 读取大小为outIndexSize的内容
- std::vector<char> animData(dataInfo.length());
- file.read(animData.data(), dataInfo.length());
- // 关闭文件
- file.close();
- isOk = model_pb.ParseFromArray(animData.data(), animData.size());
- #endif
- if(!isOk)
- {
- log("sc test android getAnimationByName model_pb失败");
- return nullptr;
- }
- }
- else{
- if (byteData.getBytes() == NULL){
- return nullptr;
- }
- if (model_pb.ParseFromArray(byteData.getBytes()+dataInfo.offset(), dataInfo.length()) == false) {
- return nullptr;
- }
- }
-
- RedAnimationBakeModel* model = new RedAnimationBakeModel("", aName);
- spine::RedBakeSpineIO::getInstance()->readAnimationBakeModel(model_pb, model, filePath);
- animateList[aFileName][aName] = model;
- return model;
- }
- }
- return nullptr;
- }
- void RedSpineBakeManage::fetchAnimations(const std::string& aFileName, std::vector<std::string>& anims) {
- auto iter = dataIndexPbList.find(aFileName);
- if (iter != dataIndexPbList.end()) {
- for (auto& iter1 : iter->second) {
- anims.push_back(iter1.first);
- }
- }
- }
- void RedSpineBakeManage::releaseAimationFile(std::string aFileName){
- //把animateList[aFileName]下所有的RedAnimationBakeModel释放
- if(animateList.find(aFileName) == animateList.end()) {
- CCASSERT(false, "没有这个键值");
- return;
- }
- std::unordered_map<std::string, RedAnimationBakeModel *> bakeModelList = animateList[aFileName];
- for(auto iter = bakeModelList.begin(); iter != bakeModelList.end(); iter++) {
- std::string animName = iter->first;
- RedAnimationBakeModel* model = iter->second;
- int slotCount = model->getSlotCount();
- for(int i = 0; i < slotCount; ++i) {
- //释放RedSlotBakeModel
- int key = model->getAllSlotKey()[i];
- RedSlotBakeModel* slot = model->getSlotFromKey(key);
- delete slot;
- }
- //释放RedAnimationBakeModel
- delete model;
- }
- animateList.erase(aFileName);
- }
- void RedSpineBakeManage::loadAnimationFileAsync(const std::string& aFileName, const std::string& aPath, bool isCharacter) {
- ///如果已经加载则直接返回
- if (animateList.find(aFileName) != animateList.end()) {
- return;
- }
- if (dataIndexPbList.find(aFileName) != dataIndexPbList.end()) {
- return;
- }
- ///获取文件全路径,保证线程安全
- std::string fileFullPath = "";
- if (aPath.size() == 0) {
- fileFullPath = FileUtils::getInstance()->fullPathForFilename(aFileName + REDSPINEBAKE_EXTENSION);
- } else {
- fileFullPath = aPath + aFileName + REDSPINEBAKE_EXTENSION;
- }
- ///文件不存在则直接返回
- if (FileUtils::getInstance()->isFileExist(fileFullPath) == false) {
- return;
- }
- ///创建异步加载请求表单
- AsyncLoadAnimationFileRequest* request = new AsyncLoadAnimationFileRequest();
- request->key = aFileName;
- request->fileFullPath = fileFullPath;
- request->isCharacter = isCharacter;
- std::unique_lock<std::mutex> ul(_requestsMtx);
- _requests.push(request);
- ul.unlock();
- ///异步线程使用懒汉式创建
- if (_loadThread == nullptr) {
- _loadThread = new std::thread(&RedSpineBakeManage::_readAnimationFileInThread, this);
- }
- ///唤醒休眠线程
- _sleepCondition.notify_one();
- }
- void RedSpineBakeManage::loadAnimationFile(const std::string& aFileName, const std::string& aPath, bool isCharacter){
- if(animateList.find(aFileName) != animateList.end()) {
- // CCASSERT(false, "重复加载");
- return;
- }
- if (dataIndexPbList.find(aFileName) != dataIndexPbList.end()) {
- return;
- }
-
- filePath = aPath;
- std::unordered_map<std::string, RedAnimationBakeModel*> datas;
- animateList[aFileName] = datas;
-
- std::string fileFullPath = "";
- if (aPath.size() == 0) {
- fileFullPath = FileUtils::getInstance()->fullPathForFilename( aFileName + REDSPINEBAKE_EXTENSION);
- } else {
- fileFullPath = aPath + aFileName + REDSPINEBAKE_EXTENSION;
- }
-
- {
- if(FileUtils::getInstance()->isFileExist( fileFullPath ) == false) {
- CCASSERT(false, "rb文件没找到");
- return;
- }
-
- google::protobuf::Map<std::string, ::RedSpineBakeProto::DataInfo> dataIndexPb;
- const cocos2d::Data& data = _parseProtoData(fileFullPath, aFileName+REDSPINEBAKE_EXTENSION, dataIndexPb, isCharacter);
- dataIndexPbList[aFileName] = dataIndexPb;
- if (data.getSize() > 0) {
- byteArrayList[aFileName] = data;
- }
- }
- }
- //*********************************
- void RedSpineBakeManage::endBakeSaveToFile(std::string aPath){
- filePath = aPath;
- //保存所有animateList到aPath
- for(auto iter = animateList.begin(); iter != animateList.end(); ++iter) {
- std::string aFileName = iter->first;
- if(aFileName.empty()) {
- continue;
- }
- std::unordered_map<std::string, RedAnimationBakeModel*> datas = iter->second;
- std::string finalPath = filePath + "/" + aFileName + REDSPINEBAKE_EXTENSION;
- spine::RedBakeSpineIO::getInstance()->write(finalPath, datas);
- }
- }
- void RedSpineBakeManage::startBake(std::string aFileName){
- fileName = aFileName;
- }
- void RedSpineBakeManage::_release() {
- if (_loadThread) {
- _loadThread->join();
- delete _loadThread;
- }
- }
- void RedSpineBakeManage::_readAnimationFileInThread() {
- while (true) {
- AsyncLoadAnimationFileRequest* request = nullptr;
- std::unique_lock<std::mutex> ul(_requestsMtx);
- if (_requests.empty() == false) {
- request = _requests.front();
- _requests.pop();
- }
- if (request == nullptr) {
- _sleepCondition.wait(ul);
- continue;
- }
- ul.unlock();
- google::protobuf::Map<std::string, ::RedSpineBakeProto::DataInfo> dataIndexPb;
- const cocos2d::Data& data = _parseProtoData(request->fileFullPath, request->key+REDSPINEBAKE_EXTENSION, dataIndexPb, request->isCharacter);
- std::string tFileName = request->key;
- if (data.getSize() > 0) {
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([this, dataIndexPb, data, tFileName](void) {
- ///都需要先判断数据是否存在,防止和主线程冲突
- if (animateList.find(tFileName) == animateList.end()) {
- std::unordered_map<std::string, RedAnimationBakeModel*> datas;
- animateList[tFileName] = datas;
- }
- if (byteArrayList.find(tFileName) == byteArrayList.end()) {
- byteArrayList[tFileName] = data;
- }
- if (dataIndexPbList.find(tFileName) == dataIndexPbList.end()) {
- dataIndexPbList[tFileName] = dataIndexPb;
- }
- });
- }
- delete request;
- }
- }
- cocos2d::Data RedSpineBakeManage::_parseProtoData(const std::string& fileFullPath, const std::string& fileName, google::protobuf::Map<std::string, ::RedSpineBakeProto::DataInfo>& dataIndexPb, bool isCharacter)
- {
- cocos2d::Data ret;
- if(!isCharacter){
- ret = cocos2d::FileUtils::getInstance()->getDataFromFile(fileFullPath);
-
- if (ret.getSize() > 0) {
- const unsigned char* dataPtr = ret.getBytes();
- // 从数据末尾读取两个32位整数
- uint32_t currentOffset, outIndexSize;
- // 获取currentOffset和outIndexSize
- std::memcpy(¤tOffset, dataPtr + (ret.getSize() - 2 * sizeof(uint32_t)), sizeof(uint32_t));
- std::memcpy(&outIndexSize, dataPtr + (ret.getSize() - sizeof(uint32_t)), sizeof(uint32_t));
- RedSpineBakeProto::BakeDataIndex dataIndex;
- bool isOk = dataIndex.ParseFromArray(ret.getBytes()+currentOffset, outIndexSize);
- if (isOk) {
- dataIndexPb = dataIndex.dataindex();
- } else {
- CCASSERT(false, "解析索引文件失败");
- }
- }
- return ret;
- }
- RedSpineBakeProto::BakeDataIndex dataIndex;
- uint32_t currentOffset, outIndexSize;
- bool isOk = false;
- #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
- JniMethodInfo methodInfo;
- jbyteArray byteArray = nullptr;
- if (JniHelper::getStaticMethodInfo(methodInfo, BinaryFileClassName, "loadData", "(Ljava/lang/String;II)[B")) {
- jstring jFileName = methodInfo.env->NewStringUTF(fileName.c_str());
-
- // 调用获取最后两个32位整数的方法
- jintArray jIntegers = (jintArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.env->GetStaticMethodID(methodInfo.classID, "getLastTwoIntegers", "(Ljava/lang/String;)[I"), jFileName);
- // 将 Java 数组拷贝到 C++ 数组
- jint* intValues = methodInfo.env->GetIntArrayElements(jIntegers, nullptr);
- currentOffset = static_cast<uint32_t>(intValues[0]);
- outIndexSize = static_cast<uint32_t>(intValues[1]);
-
- __android_log_print(ANDROID_LOG_DEBUG, "sc test android info", "%d, %d", currentOffset, outIndexSize);
- // 释放 Java 数组
- methodInfo.env->ReleaseIntArrayElements(jIntegers, intValues, JNI_ABORT);
-
- jbyteArray result = (jbyteArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, jFileName, (int)currentOffset, (int)outIndexSize);
- byteArray = (jbyteArray)methodInfo.env->NewGlobalRef(result);
- if (byteArray != nullptr) {
- jbyte* byteData = methodInfo.env->GetByteArrayElements(byteArray, NULL);
- BYTE* byteArr = (BYTE*)byteData;
- isOk = dataIndex.ParseFromArray(byteArr, outIndexSize);
- methodInfo.env->ReleaseByteArrayElements(byteArray, byteData, JNI_ABORT);
- methodInfo.env->DeleteLocalRef(result);
- methodInfo.env->DeleteLocalRef(methodInfo.classID);
- }
- else{
- isOk = false;
- }
- }
- #else
- std::ifstream file(fileFullPath, std::ios::binary | std::ios::ate);
- if (!file.is_open()) {
- CCASSERT(false, "打开文件失败");
- }
-
- // 获取文件大小
- std::streampos fileSize = file.tellg();
- // 将文件指针移动到文件末尾
- file.seekg(-2 * sizeof(uint32_t), std::ios::end);
- // 读取两个32位整数
- file.read(reinterpret_cast<char*>(¤tOffset), sizeof(uint32_t));
- file.read(reinterpret_cast<char*>(&outIndexSize), sizeof(uint32_t));
- // log("sc_test _parseProtoData %d, %d, %d", fileSize, currentOffset, outIndexSize);
- // 将文件指针移动到currentOffset的位置
- file.seekg(currentOffset, std::ios::beg);
- // 读取大小为outIndexSize的内容
- std::vector<char> indexData(outIndexSize);
- file.read(indexData.data(), outIndexSize);
- // 关闭文件
- file.close();
- // 初始化RedSpineBakeProto::BakeDataIndex
- isOk = dataIndex.ParseFromArray(indexData.data(), indexData.size());
-
- // log("sc_test _parseProtoData %s, %d", fileFullPath.c_str(), indexData.size());
- #endif
- if (isOk) {
- dataIndexPb = dataIndex.dataindex();
- } else {
- CCASSERT(false, "解析索引文件失败");
- }
- ///如果为高端机 缓存rb就进行下面这个
- if(isCharacter && CocosConfig::isCharacterRbCache()){
- ret = cocos2d::FileUtils::getInstance()->getDataFromFile(fileFullPath);
- }
-
- return ret;
- }
|