再写一个东西的mod功能,然后用了python的c/c++SDK,然后开始用得很爽,结果mingw的玄学属实把我吓到了,那个部分的一开始的源代码如下:(用的IDE:Codeblocks 2020 mingw 64 SEH)
al("Getting initialized values...");//日志输出函数
///Getting inited values
//outs: #define outs(A) cout << string(#A ":\n") << A << endl;
outs(PyObject_GetAttrString(GetPm().mlcPointer,MENU_STRINGS_ITEM));
showingStrings = getStringLists(PyObject_GetAttrString(GetPm().mlcPointer,MENU_STRINGS_ITEM));
outs(showingStrings[0]);
这是输出:
[2022-02-09 18:51:56]:652ms:This mod "More Titles" path "C:\Users\yd\AppData\Roaming\XXXX\XXXX\Mods\MT.mtmod"'s OnInit function returns False in python.It loaded fail!
load mod "C:\Users\yd\AppData\Roaming\StudyAll\MineTerraria\Mods\MT.mtmod" fail!
[2022-02-09 18:51:56]:662ms:Getting initialized values...
GetPm().mlcPointer:
0xbcd7268
Process returned -1073741819 (0xC0000005) execution time : 8.593 s
Press any key to continue.
之后我加了两句没有用的话(目的是为了看看python是不是把指针迁移了,导致出现错误),修改代码如下:
al("Getting initialized values...");
///Getting inited values
outs(PyObject_GetAttrString(GetPm().mlcPointer,MENU_STRINGS_ITEM));
outs(PyObject_GetAttrString(GetPm().kernel,"mlc"));//第一句
outs(GetPm().mlcPointer);//第二句
showingStrings = getStringLists(PyObject_GetAttrString(GetPm().mlcPointer,MENU_STRINGS_ITEM));
outs(showingStrings[0]);
结果却出现了玄学情况:
PyObject_GetAttrString(GetPm().mlcPointer,MENU_STRINGS_ITEM):
0
PyObject_GetAttrString(GetPm().kernel,"mlc"):
0xbca7268
GetPm().mlcPointer:
0xbca7268
showingStrings[0]:
Try playing Minecraft!!!!
[2022-02-09 18:55:49]:636ms:Checking mods' logs...
*****************************************************
[2022-02-09 18:55:49]:646ms:Here are the mod logs that are listed:
''
*****************************************************
它竟然没崩掉!
我只是想知道这是为什么(我还尝试了Py_Incref(GetPm().mlcPointer)与Py_Decref(GetPm().mlcPointer)来看看是不是引用的问题,然而,很可惜,崩溃了,应该不是内存引用的问题)
######崩溃的外在原因
以下是加载的"模组"python代码:
# 这个是api,还没上高中,英语不好,许多英语句子语法不对,勿喷
# mtmod_loader.py
'''
Import Suggestions:
from mtmod_loader import *
Using Docs:
Loading dods has many steps
While in version 1.0,it has only 1 step:
Initializing
Initializing:
To init,you need to have a function OnInit()
'''
# We suggest you not to change mlc directly
class ModLoaderConfig:
#Strings that shows on the menu
menuStrings = []
# Very Warning:Do not change this value,or mod loading proc will fail!
# now loading proc!DO NOT CHANGE IT!!THIS IS VERY IMPORTANT DATA
nowProc = 0
# the mod's log
modLog = ''
#the statuses
menuLock = False
'''
The Manifest file's attributes
You can easily get them
'''
class ManifestFileSets:
# Mod Name
ModName = ""
# This Mod's Version
ModVersion = ""
# The Mod's Creator
ModAuthor = ""
# The Mod's Description
ModDescription = ""
# The Only Package ID,Make sure this id is the only one!!!!
ModPackage = ""
mlc = ModLoaderConfig()
mf = ManifestFileSets()
apiVersion = "api-1.0"
MenuLocked = 2
NowIsNotIniting = 1
Suc = 0
Fail = -1
'''
Lock the menu,other mods cannot change menuString if they follows the usual steps
'''
def lockMenu():
mlc.menuLock = True
'''
Set the strings shows upon the menu
'''
def setMenuString(menuStr):
if(mlc.menuLock):
return MenuLocked
if(mlc.nowProc == 0):
mlc.menuStrings = menuStr
return Suc
else:
return NowIsNotIniting
def sms(menuStr):
return setMenuString(menuStr)
'''
Append the strings that shows on the menu
'''
def appendMenuString(nstr):
mlc.menuStrings.append(str(nstr))
def ams(nstr):
appendMenuString(nstr)
'''
Get the strings that shows on the menu
'''
def getMenuString():
return mlc.menuStrings
def gms():
return mlc.menuStrings
'''
Get the loading proc now
'''
def getLoadingProcess():
return mlc.nowProc
def glp():
return mlc.nowProc
'''
Write the program log
'''
def writeModLog(strlg):
mlc.modLog += str(strlg)
def wml(strlg):
writeModLog(strlg)
这个是模组的代码
# main.py
from mtmod_loader import *
def OnInit():
print('Initializing mod',mf.ModName);
l = getMenuString()
l.append("More Titles is a mod which adds a lots titles to the main menu screen!")
l.crashDump() #list中没有这个成员,这个是专门测试崩溃的
setMenuString(l)
print(getMenuString())
print('Done initializing mod',mf.ModName);
return False
这种问题你只有自己设断点,然后单步调试,来找到出问题的地方。仅从上面提供的信息,别人很难帮你查出问题的根源。
另外,你可以试试用boost.python库来导出C/C++写的模块到python,boost.python接口要比Python自带的SDK好用些,至少更贴近C++,更人性化些。
我寻思这种问题是不是太难了。可能没几个人会解决???
果然,解铃还须系铃人最管用,其实这个问题的思路非常简单,我在模组代码里故意加了一句会崩溃的词句,由python api可知,PyObject_CalObject会返回NULL并且raise一个exception,那么下一次调用python函数时会因为有异常直接返回NULL,并清除异常,这就解释了为什么刚开始的代码返回0后面返回有效值,因此只需要调用PyErr_Clear()就可以了,如果要处理的话还可以自己处理,另外python39.dll调试不了!!!只有自己项目的c++代码在调试的时候可以跳转,lib及dll不可以,不然别人不开源的代码就被你窥光了!
另外回答其他答题者的建议:
1.我不会将c++转成python,这会让用户下载python使得这个游戏很麻烦,而且我是c++解析python,如果再打包成python库文件,那么就是python打包c++解析python,这......会拖慢运行时间,现在加载600ms就可以进入第三个场景(除去第一个固定时长的场景),如果转为python,可能会变成1600ms.
2.我用了不支持python的库,一个不支持python的简单unzip库,还有rapidjson(不知道可不可以),另外,还用了sfml,sfml虽然支持python...但是它原生语言是c++,如果我用pysfml,那么效率又会变慢,在以后加载地图中十分致命