Fix relocated files

This commit is contained in:
PJB3005
2026-03-02 12:50:45 +01:00
parent 8c52a386d5
commit ea890d4064
5 changed files with 1329 additions and 241 deletions
+7 -1
View File
@@ -59,7 +59,13 @@ add_library(game_debug STATIC ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES})
target_compile_definitions(game_debug PRIVATE TARGET_PC VERSION=0 $<$<CONFIG:Debug>:DEBUG=1>)
# Make these properties PUBLIC so that the regular game target also sees them.
target_include_directories(game_debug PUBLIC include src assets/${DUSK_TP_VERSION} ${CMAKE_BINARY_DIR}/../${DUSK_TP_VERSION}/include build/${DUSK_TP_VERSION}/include)
target_include_directories(game_debug PUBLIC
include
src
assets/${DUSK_TP_VERSION}
libs/JSystem/include
${CMAKE_BINARY_DIR}/../${DUSK_TP_VERSION}/include
build/${DUSK_TP_VERSION}/include)
target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::si aurora::vi aurora::pad aurora::mtx)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+240 -240
View File
@@ -315,243 +315,243 @@ set(SSYSTEM_FILES
)
set(JSYSTEM_DEBUG_FILES
src/JSystem/JParticle/JPAResourceManager.cpp
src/JSystem/JParticle/JPAResource.cpp
src/JSystem/JParticle/JPABaseShape.cpp
src/JSystem/JParticle/JPAExtraShape.cpp
src/JSystem/JParticle/JPAChildShape.cpp
src/JSystem/JParticle/JPAExTexShape.cpp
src/JSystem/JParticle/JPADynamicsBlock.cpp
src/JSystem/JParticle/JPAFieldBlock.cpp
src/JSystem/JParticle/JPAKeyBlock.cpp
src/JSystem/JParticle/JPATexture.cpp
src/JSystem/JParticle/JPAResourceLoader.cpp
src/JSystem/JParticle/JPAEmitterManager.cpp
src/JSystem/JParticle/JPAEmitter.cpp
src/JSystem/JParticle/JPAParticle.cpp
src/JSystem/JParticle/JPAMath.cpp
src/JSystem/JFramework/JFWSystem.cpp
src/JSystem/JFramework/JFWDisplay.cpp
src/JSystem/J3DU/J3DUClipper.cpp
src/JSystem/J3DU/J3DUDL.cpp
src/JSystem/JKernel/JKRHeap.cpp
src/JSystem/JKernel/JKRExpHeap.cpp
src/JSystem/JKernel/JKRSolidHeap.cpp
src/JSystem/JKernel/JKRAssertHeap.cpp
src/JSystem/JKernel/JKRDisposer.cpp
src/JSystem/JKernel/JKRThread.cpp
src/JSystem/JKernel/JKRAram.cpp
src/JSystem/JKernel/JKRAramHeap.cpp
src/JSystem/JKernel/JKRAramBlock.cpp
src/JSystem/JKernel/JKRAramPiece.cpp
src/JSystem/JKernel/JKRAramStream.cpp
src/JSystem/JKernel/JKRFileLoader.cpp
src/JSystem/JKernel/JKRFileFinder.cpp
src/JSystem/JKernel/JKRFileCache.cpp
src/JSystem/JKernel/JKRArchivePub.cpp
src/JSystem/JKernel/JKRArchivePri.cpp
src/JSystem/JKernel/JKRMemArchive.cpp
src/JSystem/JKernel/JKRAramArchive.cpp
src/JSystem/JKernel/JKRDvdArchive.cpp
src/JSystem/JKernel/JKRCompArchive.cpp
src/JSystem/JKernel/JKRFile.cpp
src/JSystem/JKernel/JKRDvdFile.cpp
src/JSystem/JKernel/JKRDvdRipper.cpp
src/JSystem/JKernel/JKRDvdAramRipper.cpp
src/JSystem/JKernel/JKRDecomp.cpp
src/JSystem/JMath/JMath.cpp
src/JSystem/JMath/random.cpp
src/JSystem/JMath/JMATrigonometric.cpp
src/JSystem/JSupport/JSUList.cpp
src/JSystem/JSupport/JSUInputStream.cpp
src/JSystem/JSupport/JSUOutputStream.cpp
src/JSystem/JSupport/JSUMemoryStream.cpp
src/JSystem/JSupport/JSUFileStream.cpp
src/JSystem/JUtility/JUTCacheFont.cpp
src/JSystem/JUtility/JUTResource.cpp
src/JSystem/JUtility/JUTTexture.cpp
src/JSystem/JUtility/JUTPalette.cpp
src/JSystem/JUtility/JUTNameTab.cpp
src/JSystem/JUtility/JUTGraphFifo.cpp
src/JSystem/JUtility/JUTFont.cpp
src/JSystem/JUtility/JUTResFont.cpp
src/JSystem/JUtility/JUTDbPrint.cpp
src/JSystem/JUtility/JUTGamePad.cpp
src/JSystem/JUtility/JUTException.cpp
src/JSystem/JUtility/JUTDirectPrint.cpp
src/JSystem/JUtility/JUTAssert.cpp
src/JSystem/JUtility/JUTVideo.cpp
src/JSystem/JUtility/JUTXfb.cpp
src/JSystem/JUtility/JUTFader.cpp
src/JSystem/JUtility/JUTProcBar.cpp
src/JSystem/JUtility/JUTConsole.cpp
src/JSystem/JUtility/JUTDirectFile.cpp
src/JSystem/JUtility/JUTFontData_Ascfont_fix12.cpp
src/JSystem/JStage/JSGActor.cpp
src/JSystem/JStage/JSGAmbientLight.cpp
src/JSystem/JStage/JSGCamera.cpp
src/JSystem/JStage/JSGFog.cpp
src/JSystem/JStage/JSGLight.cpp
src/JSystem/JStage/JSGObject.cpp
src/JSystem/JStage/JSGSystem.cpp
src/JSystem/J2DGraph/J2DGrafContext.cpp
src/JSystem/J2DGraph/J2DOrthoGraph.cpp
src/JSystem/J2DGraph/J2DTevs.cpp
src/JSystem/J2DGraph/J2DMaterial.cpp
src/JSystem/J2DGraph/J2DMatBlock.cpp
src/JSystem/J2DGraph/J2DMaterialFactory.cpp
src/JSystem/J2DGraph/J2DPrint.cpp
src/JSystem/J2DGraph/J2DPane.cpp
src/JSystem/J2DGraph/J2DScreen.cpp
src/JSystem/J2DGraph/J2DWindow.cpp
src/JSystem/J2DGraph/J2DPicture.cpp
src/JSystem/J2DGraph/J2DTextBox.cpp
src/JSystem/J2DGraph/J2DWindowEx.cpp
src/JSystem/J2DGraph/J2DPictureEx.cpp
src/JSystem/J2DGraph/J2DTextBoxEx.cpp
src/JSystem/J2DGraph/J2DAnmLoader.cpp
src/JSystem/J2DGraph/J2DAnimation.cpp
src/JSystem/J2DGraph/J2DManage.cpp
src/JSystem/J3DGraphBase/J3DGD.cpp
src/JSystem/J3DGraphBase/J3DSys.cpp
src/JSystem/J3DGraphBase/J3DVertex.cpp
src/JSystem/J3DGraphBase/J3DTransform.cpp
src/JSystem/J3DGraphBase/J3DTexture.cpp
src/JSystem/J3DGraphBase/J3DPacket.cpp
src/JSystem/J3DGraphBase/J3DShapeMtx.cpp
src/JSystem/J3DGraphBase/J3DShapeDraw.cpp
src/JSystem/J3DGraphBase/J3DShape.cpp
src/JSystem/J3DGraphBase/J3DMaterial.cpp
src/JSystem/J3DGraphBase/J3DMatBlock.cpp
src/JSystem/J3DGraphBase/J3DTevs.cpp
src/JSystem/J3DGraphBase/J3DDrawBuffer.cpp
src/JSystem/J3DGraphBase/J3DStruct.cpp
src/JSystem/J3DGraphAnimator/J3DShapeTable.cpp
src/JSystem/J3DGraphAnimator/J3DJointTree.cpp
src/JSystem/J3DGraphAnimator/J3DModelData.cpp
src/JSystem/J3DGraphAnimator/J3DMtxBuffer.cpp
src/JSystem/J3DGraphAnimator/J3DModel.cpp
src/JSystem/J3DGraphAnimator/J3DAnimation.cpp
src/JSystem/J3DGraphAnimator/J3DMaterialAnm.cpp
src/JSystem/J3DGraphAnimator/J3DSkinDeform.cpp
src/JSystem/J3DGraphAnimator/J3DCluster.cpp
src/JSystem/J3DGraphAnimator/J3DJoint.cpp
src/JSystem/J3DGraphAnimator/J3DMaterialAttach.cpp
src/JSystem/J3DGraphLoader/J3DMaterialFactory.cpp
src/JSystem/J3DGraphLoader/J3DMaterialFactory_v21.cpp
src/JSystem/J3DGraphLoader/J3DClusterLoader.cpp
src/JSystem/J3DGraphLoader/J3DModelLoader.cpp
src/JSystem/J3DGraphLoader/J3DModelLoaderCalcSize.cpp
src/JSystem/J3DGraphLoader/J3DJointFactory.cpp
src/JSystem/J3DGraphLoader/J3DShapeFactory.cpp
src/JSystem/J3DGraphLoader/J3DAnmLoader.cpp
src/JSystem/JStudio/JStudio/ctb.cpp
src/JSystem/JStudio/JStudio/ctb-data.cpp
src/JSystem/JStudio/JStudio/functionvalue.cpp
src/JSystem/JStudio/JStudio/fvb.cpp
src/JSystem/JStudio/JStudio/fvb-data.cpp
src/JSystem/JStudio/JStudio/fvb-data-parse.cpp
src/JSystem/JStudio/JStudio/jstudio-control.cpp
src/JSystem/JStudio/JStudio/jstudio-data.cpp
src/JSystem/JStudio/JStudio/jstudio-math.cpp
src/JSystem/JStudio/JStudio/jstudio-object.cpp
src/JSystem/JStudio/JStudio/object-id.cpp
src/JSystem/JStudio/JStudio/stb.cpp
src/JSystem/JStudio/JStudio/stb-data-parse.cpp
src/JSystem/JStudio/JStudio/stb-data.cpp
src/JSystem/JStudio/JStudio_JStage/control.cpp
src/JSystem/JStudio/JStudio_JStage/object.cpp
src/JSystem/JStudio/JStudio_JStage/object-actor.cpp
src/JSystem/JStudio/JStudio_JStage/object-ambientlight.cpp
src/JSystem/JStudio/JStudio_JStage/object-camera.cpp
src/JSystem/JStudio/JStudio_JStage/object-fog.cpp
src/JSystem/JStudio/JStudio_JStage/object-light.cpp
src/JSystem/JStudio/JStudio_JAudio2/control.cpp
src/JSystem/JStudio/JStudio_JAudio2/object-sound.cpp
src/JSystem/JStudio/JStudio_JParticle/control.cpp
src/JSystem/JStudio/JStudio_JParticle/object-particle.cpp
src/JSystem/JAudio2/JASCalc.cpp
src/JSystem/JAudio2/JASTaskThread.cpp
src/JSystem/JAudio2/JASDvdThread.cpp
src/JSystem/JAudio2/JASCallback.cpp
src/JSystem/JAudio2/JASHeapCtrl.cpp
src/JSystem/JAudio2/JASResArcLoader.cpp
src/JSystem/JAudio2/JASProbe.cpp
src/JSystem/JAudio2/JASReport.cpp
src/JSystem/JAudio2/JASCmdStack.cpp
src/JSystem/JAudio2/JASTrack.cpp
src/JSystem/JAudio2/JASTrackPort.cpp
src/JSystem/JAudio2/JASRegisterParam.cpp
src/JSystem/JAudio2/JASSeqCtrl.cpp
src/JSystem/JAudio2/JASSeqParser.cpp
src/JSystem/JAudio2/JASSeqReader.cpp
src/JSystem/JAudio2/JASAramStream.cpp
src/JSystem/JAudio2/JASBank.cpp
src/JSystem/JAudio2/JASBasicBank.cpp
src/JSystem/JAudio2/JASVoiceBank.cpp
src/JSystem/JAudio2/JASBasicInst.cpp
src/JSystem/JAudio2/JASDrumSet.cpp
src/JSystem/JAudio2/JASBasicWaveBank.cpp
src/JSystem/JAudio2/JASSimpleWaveBank.cpp
src/JSystem/JAudio2/JASWSParser.cpp
src/JSystem/JAudio2/JASBNKParser.cpp
src/JSystem/JAudio2/JASWaveArcLoader.cpp
src/JSystem/JAudio2/JASChannel.cpp
src/JSystem/JAudio2/JASLfo.cpp
src/JSystem/JAudio2/JASOscillator.cpp
src/JSystem/JAudio2/JASAiCtrl.cpp
src/JSystem/JAudio2/JASAudioThread.cpp
src/JSystem/JAudio2/JASAudioReseter.cpp
src/JSystem/JAudio2/JASDSPChannel.cpp
src/JSystem/JAudio2/JASDSPInterface.cpp
src/JSystem/JAudio2/JASDriverIF.cpp
src/JSystem/JAudio2/JASSoundParams.cpp
src/JSystem/JAudio2/dspproc.cpp
src/JSystem/JAudio2/dsptask.cpp
src/JSystem/JAudio2/osdsp.cpp
src/JSystem/JAudio2/osdsp_task.cpp
src/JSystem/JAudio2/JAIAudible.cpp
src/JSystem/JAudio2/JAIAudience.cpp
src/JSystem/JAudio2/JAISe.cpp
src/JSystem/JAudio2/JAISeMgr.cpp
src/JSystem/JAudio2/JAISeq.cpp
src/JSystem/JAudio2/JAISeqDataMgr.cpp
src/JSystem/JAudio2/JAISeqMgr.cpp
src/JSystem/JAudio2/JAISound.cpp
src/JSystem/JAudio2/JAISoundChild.cpp
src/JSystem/JAudio2/JAISoundHandles.cpp
src/JSystem/JAudio2/JAISoundInfo.cpp
src/JSystem/JAudio2/JAISoundParams.cpp
src/JSystem/JAudio2/JAISoundStarter.cpp
src/JSystem/JAudio2/JAIStream.cpp
src/JSystem/JAudio2/JAIStreamDataMgr.cpp
src/JSystem/JAudio2/JAIStreamMgr.cpp
src/JSystem/JAudio2/JAUAudioArcInterpreter.cpp
src/JSystem/JAudio2/JAUAudioArcLoader.cpp
src/JSystem/JAudio2/JAUAudioMgr.cpp
src/JSystem/JAudio2/JAUBankTable.cpp
src/JSystem/JAudio2/JAUClusterSound.cpp
src/JSystem/JAudio2/JAUInitializer.cpp
src/JSystem/JAudio2/JAUSectionHeap.cpp
src/JSystem/JAudio2/JAUSeqCollection.cpp
src/JSystem/JAudio2/JAUSeqDataBlockMgr.cpp
src/JSystem/JAudio2/JAUSoundAnimator.cpp
src/JSystem/JAudio2/JAUSoundTable.cpp
src/JSystem/JAudio2/JAUStreamFileTable.cpp
src/JSystem/JMessage/control.cpp
src/JSystem/JMessage/data.cpp
src/JSystem/JMessage/processor.cpp
src/JSystem/JMessage/resource.cpp
src/JSystem/JMessage/locale.cpp
src/JSystem/JGadget/binary.cpp
src/JSystem/JGadget/define.cpp
src/JSystem/JGadget/linklist.cpp
src/JSystem/JGadget/std-vector.cpp
src/JSystem/JHostIO/JORHostInfo.cpp
src/JSystem/JHostIO/JORServer.cpp
src/JSystem/JHostIO/JHIhioASync.cpp
src/JSystem/JHostIO/JHIRMcc.cpp
src/JSystem/JHostIO/JHIMccBuf.cpp
libs/JSystem/src/JParticle/JPAResourceManager.cpp
libs/JSystem/src/JParticle/JPAResource.cpp
libs/JSystem/src/JParticle/JPABaseShape.cpp
libs/JSystem/src/JParticle/JPAExtraShape.cpp
libs/JSystem/src/JParticle/JPAChildShape.cpp
libs/JSystem/src/JParticle/JPAExTexShape.cpp
libs/JSystem/src/JParticle/JPADynamicsBlock.cpp
libs/JSystem/src/JParticle/JPAFieldBlock.cpp
libs/JSystem/src/JParticle/JPAKeyBlock.cpp
libs/JSystem/src/JParticle/JPATexture.cpp
libs/JSystem/src/JParticle/JPAResourceLoader.cpp
libs/JSystem/src/JParticle/JPAEmitterManager.cpp
libs/JSystem/src/JParticle/JPAEmitter.cpp
libs/JSystem/src/JParticle/JPAParticle.cpp
libs/JSystem/src/JParticle/JPAMath.cpp
libs/JSystem/src/JFramework/JFWSystem.cpp
libs/JSystem/src/JFramework/JFWDisplay.cpp
libs/JSystem/src/J3DU/J3DUClipper.cpp
libs/JSystem/src/J3DU/J3DUDL.cpp
libs/JSystem/src/JKernel/JKRHeap.cpp
libs/JSystem/src/JKernel/JKRExpHeap.cpp
libs/JSystem/src/JKernel/JKRSolidHeap.cpp
libs/JSystem/src/JKernel/JKRAssertHeap.cpp
libs/JSystem/src/JKernel/JKRDisposer.cpp
libs/JSystem/src/JKernel/JKRThread.cpp
libs/JSystem/src/JKernel/JKRAram.cpp
libs/JSystem/src/JKernel/JKRAramHeap.cpp
libs/JSystem/src/JKernel/JKRAramBlock.cpp
libs/JSystem/src/JKernel/JKRAramPiece.cpp
libs/JSystem/src/JKernel/JKRAramStream.cpp
libs/JSystem/src/JKernel/JKRFileLoader.cpp
libs/JSystem/src/JKernel/JKRFileFinder.cpp
libs/JSystem/src/JKernel/JKRFileCache.cpp
libs/JSystem/src/JKernel/JKRArchivePub.cpp
libs/JSystem/src/JKernel/JKRArchivePri.cpp
libs/JSystem/src/JKernel/JKRMemArchive.cpp
libs/JSystem/src/JKernel/JKRAramArchive.cpp
libs/JSystem/src/JKernel/JKRDvdArchive.cpp
libs/JSystem/src/JKernel/JKRCompArchive.cpp
libs/JSystem/src/JKernel/JKRFile.cpp
libs/JSystem/src/JKernel/JKRDvdFile.cpp
libs/JSystem/src/JKernel/JKRDvdRipper.cpp
libs/JSystem/src/JKernel/JKRDvdAramRipper.cpp
libs/JSystem/src/JKernel/JKRDecomp.cpp
libs/JSystem/src/JMath/JMath.cpp
libs/JSystem/src/JMath/random.cpp
libs/JSystem/src/JMath/JMATrigonometric.cpp
libs/JSystem/src/JSupport/JSUList.cpp
libs/JSystem/src/JSupport/JSUInputStream.cpp
libs/JSystem/src/JSupport/JSUOutputStream.cpp
libs/JSystem/src/JSupport/JSUMemoryStream.cpp
libs/JSystem/src/JSupport/JSUFileStream.cpp
libs/JSystem/src/JUtility/JUTCacheFont.cpp
libs/JSystem/src/JUtility/JUTResource.cpp
libs/JSystem/src/JUtility/JUTTexture.cpp
libs/JSystem/src/JUtility/JUTPalette.cpp
libs/JSystem/src/JUtility/JUTNameTab.cpp
libs/JSystem/src/JUtility/JUTGraphFifo.cpp
libs/JSystem/src/JUtility/JUTFont.cpp
libs/JSystem/src/JUtility/JUTResFont.cpp
libs/JSystem/src/JUtility/JUTDbPrint.cpp
libs/JSystem/src/JUtility/JUTGamePad.cpp
libs/JSystem/src/JUtility/JUTException.cpp
libs/JSystem/src/JUtility/JUTDirectPrint.cpp
libs/JSystem/src/JUtility/JUTAssert.cpp
libs/JSystem/src/JUtility/JUTVideo.cpp
libs/JSystem/src/JUtility/JUTXfb.cpp
libs/JSystem/src/JUtility/JUTFader.cpp
libs/JSystem/src/JUtility/JUTProcBar.cpp
libs/JSystem/src/JUtility/JUTConsole.cpp
libs/JSystem/src/JUtility/JUTDirectFile.cpp
libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp
libs/JSystem/src/JStage/JSGActor.cpp
libs/JSystem/src/JStage/JSGAmbientLight.cpp
libs/JSystem/src/JStage/JSGCamera.cpp
libs/JSystem/src/JStage/JSGFog.cpp
libs/JSystem/src/JStage/JSGLight.cpp
libs/JSystem/src/JStage/JSGObject.cpp
libs/JSystem/src/JStage/JSGSystem.cpp
libs/JSystem/src/J2DGraph/J2DGrafContext.cpp
libs/JSystem/src/J2DGraph/J2DOrthoGraph.cpp
libs/JSystem/src/J2DGraph/J2DTevs.cpp
libs/JSystem/src/J2DGraph/J2DMaterial.cpp
libs/JSystem/src/J2DGraph/J2DMatBlock.cpp
libs/JSystem/src/J2DGraph/J2DMaterialFactory.cpp
libs/JSystem/src/J2DGraph/J2DPrint.cpp
libs/JSystem/src/J2DGraph/J2DPane.cpp
libs/JSystem/src/J2DGraph/J2DScreen.cpp
libs/JSystem/src/J2DGraph/J2DWindow.cpp
libs/JSystem/src/J2DGraph/J2DPicture.cpp
libs/JSystem/src/J2DGraph/J2DTextBox.cpp
libs/JSystem/src/J2DGraph/J2DWindowEx.cpp
libs/JSystem/src/J2DGraph/J2DPictureEx.cpp
libs/JSystem/src/J2DGraph/J2DTextBoxEx.cpp
libs/JSystem/src/J2DGraph/J2DAnmLoader.cpp
libs/JSystem/src/J2DGraph/J2DAnimation.cpp
libs/JSystem/src/J2DGraph/J2DManage.cpp
libs/JSystem/src/J3DGraphBase/J3DGD.cpp
libs/JSystem/src/J3DGraphBase/J3DSys.cpp
libs/JSystem/src/J3DGraphBase/J3DVertex.cpp
libs/JSystem/src/J3DGraphBase/J3DTransform.cpp
libs/JSystem/src/J3DGraphBase/J3DTexture.cpp
libs/JSystem/src/J3DGraphBase/J3DPacket.cpp
libs/JSystem/src/J3DGraphBase/J3DShapeMtx.cpp
libs/JSystem/src/J3DGraphBase/J3DShapeDraw.cpp
libs/JSystem/src/J3DGraphBase/J3DShape.cpp
libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp
libs/JSystem/src/J3DGraphBase/J3DMatBlock.cpp
libs/JSystem/src/J3DGraphBase/J3DTevs.cpp
libs/JSystem/src/J3DGraphBase/J3DDrawBuffer.cpp
libs/JSystem/src/J3DGraphBase/J3DStruct.cpp
libs/JSystem/src/J3DGraphAnimator/J3DShapeTable.cpp
libs/JSystem/src/J3DGraphAnimator/J3DJointTree.cpp
libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp
libs/JSystem/src/J3DGraphAnimator/J3DMtxBuffer.cpp
libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp
libs/JSystem/src/J3DGraphAnimator/J3DAnimation.cpp
libs/JSystem/src/J3DGraphAnimator/J3DMaterialAnm.cpp
libs/JSystem/src/J3DGraphAnimator/J3DSkinDeform.cpp
libs/JSystem/src/J3DGraphAnimator/J3DCluster.cpp
libs/JSystem/src/J3DGraphAnimator/J3DJoint.cpp
libs/JSystem/src/J3DGraphAnimator/J3DMaterialAttach.cpp
libs/JSystem/src/J3DGraphLoader/J3DMaterialFactory.cpp
libs/JSystem/src/J3DGraphLoader/J3DMaterialFactory_v21.cpp
libs/JSystem/src/J3DGraphLoader/J3DClusterLoader.cpp
libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp
libs/JSystem/src/J3DGraphLoader/J3DModelLoaderCalcSize.cpp
libs/JSystem/src/J3DGraphLoader/J3DJointFactory.cpp
libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp
libs/JSystem/src/J3DGraphLoader/J3DAnmLoader.cpp
libs/JSystem/src/JStudio/JStudio/ctb.cpp
libs/JSystem/src/JStudio/JStudio/ctb-data.cpp
libs/JSystem/src/JStudio/JStudio/functionvalue.cpp
libs/JSystem/src/JStudio/JStudio/fvb.cpp
libs/JSystem/src/JStudio/JStudio/fvb-data.cpp
libs/JSystem/src/JStudio/JStudio/fvb-data-parse.cpp
libs/JSystem/src/JStudio/JStudio/jstudio-control.cpp
libs/JSystem/src/JStudio/JStudio/jstudio-data.cpp
libs/JSystem/src/JStudio/JStudio/jstudio-math.cpp
libs/JSystem/src/JStudio/JStudio/jstudio-object.cpp
libs/JSystem/src/JStudio/JStudio/object-id.cpp
libs/JSystem/src/JStudio/JStudio/stb.cpp
libs/JSystem/src/JStudio/JStudio/stb-data-parse.cpp
libs/JSystem/src/JStudio/JStudio/stb-data.cpp
libs/JSystem/src/JStudio/JStudio_JStage/control.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object-actor.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object-ambientlight.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object-camera.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object-fog.cpp
libs/JSystem/src/JStudio/JStudio_JStage/object-light.cpp
libs/JSystem/src/JStudio/JStudio_JAudio2/control.cpp
libs/JSystem/src/JStudio/JStudio_JAudio2/object-sound.cpp
libs/JSystem/src/JStudio/JStudio_JParticle/control.cpp
libs/JSystem/src/JStudio/JStudio_JParticle/object-particle.cpp
libs/JSystem/src/JAudio2/JASCalc.cpp
libs/JSystem/src/JAudio2/JASTaskThread.cpp
libs/JSystem/src/JAudio2/JASDvdThread.cpp
libs/JSystem/src/JAudio2/JASCallback.cpp
libs/JSystem/src/JAudio2/JASHeapCtrl.cpp
libs/JSystem/src/JAudio2/JASResArcLoader.cpp
libs/JSystem/src/JAudio2/JASProbe.cpp
libs/JSystem/src/JAudio2/JASReport.cpp
libs/JSystem/src/JAudio2/JASCmdStack.cpp
libs/JSystem/src/JAudio2/JASTrack.cpp
libs/JSystem/src/JAudio2/JASTrackPort.cpp
libs/JSystem/src/JAudio2/JASRegisterParam.cpp
libs/JSystem/src/JAudio2/JASSeqCtrl.cpp
libs/JSystem/src/JAudio2/JASSeqParser.cpp
libs/JSystem/src/JAudio2/JASSeqReader.cpp
libs/JSystem/src/JAudio2/JASAramStream.cpp
libs/JSystem/src/JAudio2/JASBank.cpp
libs/JSystem/src/JAudio2/JASBasicBank.cpp
libs/JSystem/src/JAudio2/JASVoiceBank.cpp
libs/JSystem/src/JAudio2/JASBasicInst.cpp
libs/JSystem/src/JAudio2/JASDrumSet.cpp
libs/JSystem/src/JAudio2/JASBasicWaveBank.cpp
libs/JSystem/src/JAudio2/JASSimpleWaveBank.cpp
libs/JSystem/src/JAudio2/JASWSParser.cpp
libs/JSystem/src/JAudio2/JASBNKParser.cpp
libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp
libs/JSystem/src/JAudio2/JASChannel.cpp
libs/JSystem/src/JAudio2/JASLfo.cpp
libs/JSystem/src/JAudio2/JASOscillator.cpp
libs/JSystem/src/JAudio2/JASAiCtrl.cpp
libs/JSystem/src/JAudio2/JASAudioThread.cpp
libs/JSystem/src/JAudio2/JASAudioReseter.cpp
libs/JSystem/src/JAudio2/JASDSPChannel.cpp
libs/JSystem/src/JAudio2/JASDSPInterface.cpp
libs/JSystem/src/JAudio2/JASDriverIF.cpp
libs/JSystem/src/JAudio2/JASSoundParams.cpp
libs/JSystem/src/JAudio2/dspproc.cpp
libs/JSystem/src/JAudio2/dsptask.cpp
libs/JSystem/src/JAudio2/osdsp.cpp
libs/JSystem/src/JAudio2/osdsp_task.cpp
libs/JSystem/src/JAudio2/JAIAudible.cpp
libs/JSystem/src/JAudio2/JAIAudience.cpp
libs/JSystem/src/JAudio2/JAISe.cpp
libs/JSystem/src/JAudio2/JAISeMgr.cpp
libs/JSystem/src/JAudio2/JAISeq.cpp
libs/JSystem/src/JAudio2/JAISeqDataMgr.cpp
libs/JSystem/src/JAudio2/JAISeqMgr.cpp
libs/JSystem/src/JAudio2/JAISound.cpp
libs/JSystem/src/JAudio2/JAISoundChild.cpp
libs/JSystem/src/JAudio2/JAISoundHandles.cpp
libs/JSystem/src/JAudio2/JAISoundInfo.cpp
libs/JSystem/src/JAudio2/JAISoundParams.cpp
libs/JSystem/src/JAudio2/JAISoundStarter.cpp
libs/JSystem/src/JAudio2/JAIStream.cpp
libs/JSystem/src/JAudio2/JAIStreamDataMgr.cpp
libs/JSystem/src/JAudio2/JAIStreamMgr.cpp
libs/JSystem/src/JAudio2/JAUAudioArcInterpreter.cpp
libs/JSystem/src/JAudio2/JAUAudioArcLoader.cpp
libs/JSystem/src/JAudio2/JAUAudioMgr.cpp
libs/JSystem/src/JAudio2/JAUBankTable.cpp
libs/JSystem/src/JAudio2/JAUClusterSound.cpp
libs/JSystem/src/JAudio2/JAUInitializer.cpp
libs/JSystem/src/JAudio2/JAUSectionHeap.cpp
libs/JSystem/src/JAudio2/JAUSeqCollection.cpp
libs/JSystem/src/JAudio2/JAUSeqDataBlockMgr.cpp
libs/JSystem/src/JAudio2/JAUSoundAnimator.cpp
libs/JSystem/src/JAudio2/JAUSoundTable.cpp
libs/JSystem/src/JAudio2/JAUStreamFileTable.cpp
libs/JSystem/src/JMessage/control.cpp
libs/JSystem/src/JMessage/data.cpp
libs/JSystem/src/JMessage/processor.cpp
libs/JSystem/src/JMessage/resource.cpp
libs/JSystem/src/JMessage/locale.cpp
libs/JSystem/src/JGadget/binary.cpp
libs/JSystem/src/JGadget/define.cpp
libs/JSystem/src/JGadget/linklist.cpp
libs/JSystem/src/JGadget/std-vector.cpp
libs/JSystem/src/JHostIO/JORHostInfo.cpp
libs/JSystem/src/JHostIO/JORServer.cpp
libs/JSystem/src/JHostIO/JHIhioASync.cpp
libs/JSystem/src/JHostIO/JHIRMcc.cpp
libs/JSystem/src/JHostIO/JHIMccBuf.cpp
)
set(JSYSTEM_FILES
@@ -1333,7 +1333,7 @@ set(DUSK_FILES
src/dusk/imgui/debug_overlay.cpp
src/dusk/imgui/heaps.cpp
src/dusk/offset_ptr.cpp
src/dolphin/os/OSContext.cpp
src/dolphin/os/OSThread.cpp
src/dolphin/os/OSMutex.cpp
src/dusk/OSContext.cpp
src/dusk/OSThread.cpp
src/dusk/OSMutex.cpp
)
+92
View File
@@ -0,0 +1,92 @@
// OSContext.cpp - PC implementation of GameCube OSContext API
// Replaces PowerPC assembly context switching with minimal PC stubs.
// On PC there is no register-level context save/restore; the OS handles
// thread contexts natively via std::thread.
#include <dolphin/dolphin.h>
#include <dolphin/os.h>
#include <cstring>
#ifdef __cplusplus
extern "C" {
#endif
// --- Current context pointer (per-process, not per-thread) ---
static OSContext* sCurrentContext = nullptr;
OSContext* OSGetCurrentContext(void) {
return sCurrentContext;
}
void OSSetCurrentContext(OSContext* context) {
sCurrentContext = context;
}
void OSClearContext(OSContext* context) {
if (!context) return;
context->mode = 0;
context->state = 0;
}
void OSInitContext(OSContext* context, u32 pc, u32 newsp) {
if (!context) return;
memset(context, 0, sizeof(OSContext));
context->srr0 = pc;
context->gpr[1] = newsp;
}
u32 OSSaveContext(OSContext* context) {
// On PC we don't save PowerPC registers.
// Return 0 = "context was just saved" (as opposed to 1 = "restored from save").
return 0;
}
void OSLoadContext(OSContext* context) {
// No-op on PC (no PowerPC register restore)
}
void OSDumpContext(OSContext* context) {
if (!context) {
OSReport("[PC] OSDumpContext: NULL context\n");
return;
}
OSReport("[PC] OSDumpContext: context at %p (no register info on PC)\n", context);
}
void OSFillFPUContext(OSContext* context) {
// No-op on PC (no PowerPC FPU state)
}
void OSLoadFPUContext(OSContext* fpucontext) {
// No-op on PC
}
void OSSaveFPUContext(OSContext* fpucontext) {
// No-op on PC
}
u32 OSGetStackPointer(void) {
// Return approximate stack pointer
volatile u32 dummy;
return (u32)(uintptr_t)&dummy;
}
u32 OSSwitchStack(u32 newsp) {
// Not meaningful on PC - return current sp
return OSGetStackPointer();
}
int OSSwitchFiber(u32 pc, u32 newsp) {
// Not meaningful on PC
OSReport("[PC] OSSwitchFiber: not supported on PC\n");
return 0;
}
void __OSContextInit(void) {
// On GC this installs the FPU exception handler.
// On PC nothing to do.
}
#ifdef __cplusplus
}
#endif
+243
View File
@@ -0,0 +1,243 @@
// OSMutex.cpp - PC implementation of GameCube OSMutex/OSCond API
// Uses std::recursive_mutex and std::condition_variable_any behind the
// unchanged GameCube C API. The OSMutex struct layout is preserved so
// game code can read its fields.
#include <dolphin/dolphin.h>
#include <dolphin/os.h>
#include <mutex>
#include <condition_variable>
#include <unordered_map>
#include <memory>
#include <cstdlib>
// ============================================================================
// Malloc-based allocator to bypass JKRHeap operator new/delete
// Without this, side-table allocations call operator new -> JKRHeap::alloc
// -> OSLockMutex -> GetMutexData -> operator new ... infinite recursion.
// ============================================================================
template<typename T>
struct MallocAllocator {
using value_type = T;
MallocAllocator() = default;
template<typename U> MallocAllocator(const MallocAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
void* p = std::malloc(n * sizeof(T));
if (!p) throw std::bad_alloc();
return static_cast<T*>(p);
}
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
template<typename U> bool operator==(const MallocAllocator<U>&) const noexcept { return true; }
template<typename U> bool operator!=(const MallocAllocator<U>&) const noexcept { return false; }
};
template<typename T>
struct MallocDeleter {
void operator()(T* p) const {
p->~T();
std::free(p);
}
};
template<typename T, typename... Args>
std::unique_ptr<T, MallocDeleter<T>> make_malloc_unique(Args&&... args) {
void* mem = std::malloc(sizeof(T));
if (!mem) throw std::bad_alloc();
T* obj = new (mem) T(std::forward<Args>(args)...);
return std::unique_ptr<T, MallocDeleter<T>>(obj);
}
// ============================================================================
// Side-table: native mutex per OSMutex
// ============================================================================
struct PCMutexData {
std::recursive_mutex nativeMutex;
};
template<typename K, typename V>
using MallocMap = std::unordered_map<K, V, std::hash<K>, std::equal_to<K>,
MallocAllocator<std::pair<const K, V>>>;
// Lazy-initialized to avoid DLL static init crashes
static std::mutex& GetMutexMapMutex() {
static std::mutex mtx;
return mtx;
}
static MallocMap<OSMutex*, std::unique_ptr<PCMutexData, MallocDeleter<PCMutexData>>>& GetMutexMap() {
static MallocMap<OSMutex*, std::unique_ptr<PCMutexData, MallocDeleter<PCMutexData>>> map;
return map;
}
static PCMutexData& GetMutexData(OSMutex* mutex) {
std::lock_guard<std::mutex> lock(GetMutexMapMutex());
auto& map = GetMutexMap();
auto it = map.find(mutex);
if (it == map.end()) {
auto result = map.emplace(mutex, make_malloc_unique<PCMutexData>());
return *result.first->second;
}
return *it->second;
}
// ============================================================================
// Side-table: native condition variable per OSCond
// ============================================================================
struct PCCondData {
std::condition_variable_any cv;
};
// Lazy-initialized to avoid DLL static init crashes
static std::mutex& GetCondMapMutex() {
static std::mutex mtx;
return mtx;
}
static MallocMap<OSCond*, std::unique_ptr<PCCondData, MallocDeleter<PCCondData>>>& GetCondMap() {
static MallocMap<OSCond*, std::unique_ptr<PCCondData, MallocDeleter<PCCondData>>> map;
return map;
}
static PCCondData& GetCondData(OSCond* cond) {
std::lock_guard<std::mutex> lock(GetCondMapMutex());
auto& map = GetCondMap();
auto it = map.find(cond);
if (it == map.end()) {
auto result = map.emplace(cond, make_malloc_unique<PCCondData>());
return *result.first->second;
}
return *it->second;
}
// ============================================================================
// C API functions
// ============================================================================
extern "C" {
void OSInitMutex(OSMutex* mutex) {
if (!mutex) return;
OSInitThreadQueue(&mutex->queue);
mutex->thread = nullptr;
mutex->count = 0;
// Create/reset side-table entry
GetMutexData(mutex);
}
void OSLockMutex(OSMutex* mutex) {
if (!mutex) return;
PCMutexData& data = GetMutexData(mutex);
data.nativeMutex.lock();
// Update GC-visible fields
OSThread* currentThread = OSGetCurrentThread();
mutex->thread = currentThread;
mutex->count++;
}
void OSUnlockMutex(OSMutex* mutex) {
if (!mutex) return;
OSThread* currentThread = OSGetCurrentThread();
if (mutex->thread != currentThread) return;
mutex->count--;
if (mutex->count == 0) {
mutex->thread = nullptr;
}
PCMutexData& data = GetMutexData(mutex);
data.nativeMutex.unlock();
}
BOOL OSTryLockMutex(OSMutex* mutex) {
if (!mutex) return FALSE;
PCMutexData& data = GetMutexData(mutex);
if (data.nativeMutex.try_lock()) {
OSThread* currentThread = OSGetCurrentThread();
mutex->thread = currentThread;
mutex->count++;
return TRUE;
}
return FALSE;
}
// ============================================================================
// Internal: unlock all mutexes held by a thread (called on thread exit)
// ============================================================================
void __OSUnlockAllMutex(OSThread* thread) {
// On GC this walks the thread's mutex queue.
// On PC the native mutexes are cleaned up when threads exit.
// Clear the GC-visible queue.
if (!thread) return;
thread->queueMutex.head = nullptr;
thread->queueMutex.tail = nullptr;
}
int __OSCheckDeadLock(OSThread* thread) {
// Simplified: native OS handles deadlock detection.
return 0;
}
int __OSCheckMutexes(OSThread* thread) {
return 1;
}
// ============================================================================
// Condition Variable API
// ============================================================================
void OSInitCond(OSCond* cond) {
if (!cond) return;
OSInitThreadQueue(&cond->queue);
GetCondData(cond);
}
void OSWaitCond(OSCond* cond, OSMutex* mutex) {
if (!cond || !mutex) return;
PCCondData& condData = GetCondData(cond);
PCMutexData& mutexData = GetMutexData(mutex);
// Save and clear the GC mutex state
OSThread* currentThread = OSGetCurrentThread();
s32 savedCount = mutex->count;
mutex->count = 0;
mutex->thread = nullptr;
// Unlock the recursive mutex the same number of times it was locked
for (s32 i = 0; i < savedCount; i++) {
mutexData.nativeMutex.unlock();
}
// Wait on the condition variable
{
std::unique_lock<std::recursive_mutex> lock(mutexData.nativeMutex);
condData.cv.wait(lock);
}
// Re-lock the recursive mutex the same number of times
for (s32 i = 0; i < savedCount; i++) {
mutexData.nativeMutex.lock();
}
// Restore GC mutex state
mutex->thread = currentThread;
mutex->count = savedCount;
}
void OSSignalCond(OSCond* cond) {
if (!cond) return;
PCCondData& condData = GetCondData(cond);
condData.cv.notify_all();
}
#ifdef __cplusplus
}
#endif
+747
View File
@@ -0,0 +1,747 @@
// OSThread.cpp - PC implementation of GameCube OSThread API
// Maps GameCube cooperative threading to native OS threads via std::thread.
// The OSThread struct layout is preserved so game code can read its fields.
// A side-table stores the native std::thread and synchronization primitives.
#include <dolphin/dolphin.h>
#include <dolphin/os.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <unordered_map>
#include <atomic>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <memory>
// ============================================================================
// Malloc-based allocator to bypass JKRHeap operator new/delete
// ============================================================================
template<typename T>
struct MallocAllocator {
using value_type = T;
MallocAllocator() = default;
template<typename U> MallocAllocator(const MallocAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
void* p = std::malloc(n * sizeof(T));
if (!p) throw std::bad_alloc();
return static_cast<T*>(p);
}
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
template<typename U> bool operator==(const MallocAllocator<U>&) const noexcept { return true; }
template<typename U> bool operator!=(const MallocAllocator<U>&) const noexcept { return false; }
};
template<typename T>
struct MallocDeleter {
void operator()(T* p) const {
p->~T();
std::free(p);
}
};
template<typename T, typename... Args>
std::unique_ptr<T, MallocDeleter<T>> make_malloc_unique(Args&&... args) {
void* mem = std::malloc(sizeof(T));
if (!mem) throw std::bad_alloc();
T* obj = new (mem) T(std::forward<Args>(args)...);
return std::unique_ptr<T, MallocDeleter<T>>(obj);
}
template<typename K, typename V>
using MallocMap = std::unordered_map<K, V, std::hash<K>, std::equal_to<K>,
MallocAllocator<std::pair<const K, V>>>;
// ============================================================================
// Side-table: native thread data per OSThread
// ============================================================================
struct PCThreadData {
std::thread nativeThread;
std::mutex mtx;
std::condition_variable cv;
void* (*func)(void*);
void* param;
bool started = false;
bool suspended = false;
};
// Lazy-initialized to avoid DLL static init crashes (used before DllMain completes)
static std::mutex& GetThreadDataMutex() {
static std::mutex mtx;
return mtx;
}
static MallocMap<OSThread*, std::unique_ptr<PCThreadData, MallocDeleter<PCThreadData>>>& GetThreadDataMap() {
static MallocMap<OSThread*, std::unique_ptr<PCThreadData, MallocDeleter<PCThreadData>>> map;
return map;
}
// Side-table for OSThreadQueue -> condition_variable (for OSSleepThread/OSWakeupThread)
static std::mutex& GetQueueCvMutex() {
static std::mutex mtx;
return mtx;
}
static MallocMap<OSThreadQueue*, std::unique_ptr<std::condition_variable, MallocDeleter<std::condition_variable>>>& GetQueueCvMap() {
static MallocMap<OSThreadQueue*, std::unique_ptr<std::condition_variable, MallocDeleter<std::condition_variable>>> map;
return map;
}
static std::condition_variable& GetQueueCV(OSThreadQueue* queue) {
std::lock_guard<std::mutex> lock(GetQueueCvMutex());
auto& map = GetQueueCvMap();
auto it = map.find(queue);
if (it == map.end()) {
auto result = map.emplace(queue, make_malloc_unique<std::condition_variable>());
return *result.first->second;
}
return *it->second;
}
// ============================================================================
// Thread-local current thread pointer
// ============================================================================
static thread_local OSThread* tls_currentThread = nullptr;
// ============================================================================
// Global state
// ============================================================================
static OSThread sDefaultThread;
static u8 sDefaultStack[64 * 1024];
static u32 sDefaultStackEnd = OS_THREAD_STACK_MAGIC;
OSThreadQueue __OSActiveThreadQueue;
// Global interrupt mutex (coarse-grained lock replacing interrupt disable)
// Lazy-initialized to avoid DLL static init crashes
static std::recursive_mutex& GetInterruptMutex() {
static std::recursive_mutex mtx;
return mtx;
}
static thread_local int sInterruptLockCount = 0;
// Scheduler suspend count
static std::atomic<s32> sSchedulerSuspendCount{0};
// Active thread count
static std::atomic<s32> sActiveThreadCount{0};
// Switch thread callback
static OSSwitchThreadCallback sSwitchThreadCallback = nullptr;
// ============================================================================
// Internal helpers
// ============================================================================
// Linked list macros for the active thread queue
static void EnqueueActive(OSThread* thread) {
OSThread* prev = __OSActiveThreadQueue.tail;
if (prev == nullptr) {
__OSActiveThreadQueue.head = thread;
} else {
prev->linkActive.next = thread;
}
thread->linkActive.prev = prev;
thread->linkActive.next = nullptr;
__OSActiveThreadQueue.tail = thread;
}
static void DequeueActive(OSThread* thread) {
OSThread* next = thread->linkActive.next;
OSThread* prev = thread->linkActive.prev;
if (next == nullptr) {
__OSActiveThreadQueue.tail = prev;
} else {
next->linkActive.prev = prev;
}
if (prev == nullptr) {
__OSActiveThreadQueue.head = next;
} else {
prev->linkActive.next = next;
}
thread->linkActive.next = nullptr;
thread->linkActive.prev = nullptr;
}
// Thread entry wrapper - runs on the new std::thread
static void ThreadEntryWrapper(OSThread* thread, PCThreadData* data) {
// Set thread-local pointer
tls_currentThread = thread;
// Set context pointers for this thread
OSClearContext(&thread->context);
OSSetCurrentContext(&thread->context);
thread->state = OS_THREAD_STATE_RUNNING;
// Call the actual thread function
void* result = data->func(data->param);
// Thread returned - equivalent to OSExitThread
thread->val = result;
thread->state = OS_THREAD_STATE_MORIBUND;
}
// ============================================================================
// C API functions
// ============================================================================
extern "C" {
void __OSThreadInit(void) {
memset(&sDefaultThread, 0, sizeof(OSThread));
sDefaultThread.state = OS_THREAD_STATE_RUNNING;
sDefaultThread.attr = OS_THREAD_ATTR_DETACH;
sDefaultThread.priority = 16;
sDefaultThread.base = 16;
sDefaultThread.suspend = 0;
sDefaultThread.val = (void*)(intptr_t)-1;
sDefaultThread.mutex = nullptr;
sDefaultThread.queue = nullptr;
OSInitThreadQueue(&sDefaultThread.queueJoin);
sDefaultThread.queueMutex.head = sDefaultThread.queueMutex.tail = nullptr;
sDefaultThread.link.next = sDefaultThread.link.prev = nullptr;
sDefaultThread.linkActive.next = sDefaultThread.linkActive.prev = nullptr;
// Stack pointers (JKRThread reads these)
sDefaultThread.stackBase = sDefaultStack + sizeof(sDefaultStack);
sDefaultThread.stackEnd = &sDefaultStackEnd;
sDefaultStackEnd = OS_THREAD_STACK_MAGIC;
OSClearContext(&sDefaultThread.context);
sDefaultThread.error = 0;
sDefaultThread.specific[0] = nullptr;
sDefaultThread.specific[1] = nullptr;
// Set as current thread for main thread
tls_currentThread = &sDefaultThread;
// Active queue
OSInitThreadQueue(&__OSActiveThreadQueue);
EnqueueActive(&sDefaultThread);
sActiveThreadCount = 1;
OSReport("[PC-OSThread] Thread system initialized (multi-threaded mode)\n");
}
// ============================================================================
// Thread Queue
// ============================================================================
void OSInitThreadQueue(OSThreadQueue* queue) {
if (queue) {
queue->head = queue->tail = nullptr;
}
}
// ============================================================================
// Current Thread
// ============================================================================
OSThread* OSGetCurrentThread(void) {
// Lazy-init for main thread if __OSThreadInit hasn't been called yet
if (tls_currentThread == nullptr) {
__OSThreadInit();
}
return tls_currentThread;
}
// ============================================================================
// Thread Creation
// ============================================================================
int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param,
void* stack, u32 stackSize, OSPriority priority, u16 attr) {
if (!thread) return 0;
if (priority < OS_PRIORITY_MIN || priority > OS_PRIORITY_MAX) return 0;
// Ensure thread system is initialized
OSGetCurrentThread();
memset(thread, 0, sizeof(OSThread));
thread->state = OS_THREAD_STATE_READY;
thread->attr = attr & 1u;
thread->base = priority;
thread->priority = priority;
thread->suspend = 1; // Created suspended (GC behavior)
thread->val = (void*)(intptr_t)-1;
thread->mutex = nullptr;
OSInitThreadQueue(&thread->queueJoin);
thread->queueMutex.head = thread->queueMutex.tail = nullptr;
thread->link.next = thread->link.prev = nullptr;
thread->linkActive.next = thread->linkActive.prev = nullptr;
// Stack (stack points to TOP on GameCube)
thread->stackBase = (u8*)stack;
thread->stackEnd = (u32*)((uintptr_t)stack - stackSize);
*thread->stackEnd = OS_THREAD_STACK_MAGIC;
OSClearContext(&thread->context);
thread->error = 0;
thread->specific[0] = nullptr;
thread->specific[1] = nullptr;
// Create side-table entry (but don't start the thread yet)
{
auto data = make_malloc_unique<PCThreadData>();
data->func = func;
data->param = param;
std::lock_guard<std::mutex> lock(GetThreadDataMutex());
GetThreadDataMap()[thread] = std::move(data);
}
// Add to active queue
EnqueueActive(thread);
sActiveThreadCount++;
OSReport("[PC-OSThread] Created thread %p (priority=%d, stackSize=%u)\n",
thread, priority, stackSize);
return 1;
}
// ============================================================================
// Resume / Suspend
// ============================================================================
/*
s32 OSResumeThread(OSThread* thread) {
if (!thread) return 0;
s32 prevSuspend = thread->suspend;
if (thread->suspend > 0) {
thread->suspend--;
}
if (thread->suspend == 0) {
std::lock_guard<std::mutex> lock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
PCThreadData* data = it->second.get();
if (!data->started) {
// First resume: launch the native thread
data->started = true;
data->suspended = false;
data->nativeThread = std::thread(ThreadEntryWrapper, thread, data);
data->nativeThread.detach();
OSReport("[PC-OSThread] Started thread %p\n", thread);
} else if (data->suspended) {
// Resume from suspension: signal the CV
data->suspended = false;
data->cv.notify_one();
}
}
}
return prevSuspend;
}
s32 OSSuspendThread(OSThread* thread) {
if (!thread) return 0;
s32 prevSuspend = thread->suspend;
thread->suspend++;
if (prevSuspend == 0) {
std::lock_guard<std::mutex> lock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
PCThreadData* data = it->second.get();
if (data->started) {
data->suspended = true;
// The thread must check its suspended flag and wait
}
}
}
return prevSuspend;
}
*/
// ============================================================================
// Resume / Suspend
// ============================================================================
s32 OSResumeThread(OSThread* thread) {
if (!thread)
return 0;
s32 prevSuspend = thread->suspend;
if (thread->suspend > 0) {
thread->suspend--;
}
// Only wake up if suspend count drops to 0
if (thread->suspend == 0) {
PCThreadData* data = nullptr;
// Lock the global map to safely retrieve our thread data pointer
{
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
data = it->second.get();
}
}
if (data) {
// Lock the specific thread mutex to safely modify state and notify
std::unique_lock<std::mutex> threadLock(data->mtx);
if (!data->started) {
// First resume: launch the native thread
data->started = true;
data->suspended = false;
// Unlock before launching to avoid potential deadlocks in thread initialization
threadLock.unlock();
data->nativeThread = std::thread(ThreadEntryWrapper, thread, data);
data->nativeThread.detach();
OSReport("[PC-OSThread] Started thread %p\n", thread);
} else {
// Resume from suspension: signal the condition variable
// IMPORTANT: Set suspended to false BEFORE notifying to pass the wait predicate
data->suspended = false;
data->cv.notify_all();
}
}
}
return prevSuspend;
}
s32 OSSuspendThread(OSThread* thread) {
if (!thread)
return 0;
s32 prevSuspend = thread->suspend;
thread->suspend++;
// If transitioning from running (0) to suspended (1)
if (prevSuspend == 0) {
PCThreadData* data = nullptr;
// Lock the global map to find our thread data
{
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
data = it->second.get();
}
}
if (data && data->started) {
std::unique_lock<std::mutex> threadLock(data->mtx);
data->suspended = true;
// FIX: If the thread is suspending ITSELF, we must block execution here.
// This replicates the GameCube behavior where OSSuspendThread yields the CPU
// immediately.
if (thread == OSGetCurrentThread()) {
// Block until 'suspended' becomes false (set by OSResumeThread)
// The predicate protects against spurious wakeups.
data->cv.wait(threadLock, [data] { return !data->suspended; });
} else {
// NOTE: Suspending *other* threads is difficult in C++ std::thread
// without cooperative checkpoints or platform-specific hacks.
// For now, we only set the flag. The target thread would need to check 'suspended'
// periodically.
}
}
}
return prevSuspend;
}
// ============================================================================
// Sleep / Wakeup (thread queue based)
// ============================================================================
void OSSleepThread(OSThreadQueue* queue) {
if (!queue) return;
OSThread* currentThread = OSGetCurrentThread();
if (!currentThread) return;
currentThread->state = OS_THREAD_STATE_WAITING;
currentThread->queue = queue;
// Enqueue into the thread queue
OSThread* prev = queue->tail;
if (prev == nullptr) {
queue->head = currentThread;
} else {
prev->link.next = currentThread;
}
currentThread->link.prev = prev;
currentThread->link.next = nullptr;
queue->tail = currentThread;
// Wait on the condition variable for this queue
std::condition_variable& cv = GetQueueCV(queue);
std::unique_lock<std::mutex> lock(GetQueueCvMutex());
cv.wait(lock, [currentThread]() {
return currentThread->state != OS_THREAD_STATE_WAITING;
});
}
void OSWakeupThread(OSThreadQueue* queue) {
if (!queue) return;
// Wake all threads in the queue
OSThread* thread = queue->head;
while (thread) {
OSThread* next = thread->link.next;
thread->state = OS_THREAD_STATE_READY;
thread->link.next = nullptr;
thread->link.prev = nullptr;
thread->queue = nullptr;
thread = next;
}
queue->head = queue->tail = nullptr;
// Notify all waiters
std::condition_variable& cv = GetQueueCV(queue);
cv.notify_all();
}
// ============================================================================
// Exit / Cancel / Detach / Join
// ============================================================================
void OSExitThread(void* val) {
OSThread* currentThread = OSGetCurrentThread();
if (!currentThread) return;
currentThread->val = val;
if (currentThread->attr & OS_THREAD_ATTR_DETACH) {
DequeueActive(currentThread);
currentThread->state = 0;
} else {
currentThread->state = OS_THREAD_STATE_MORIBUND;
}
// Wake anyone waiting to join
OSWakeupThread(&currentThread->queueJoin);
sActiveThreadCount--;
}
void OSCancelThread(OSThread* thread) {
if (!thread) return;
if (thread->attr & OS_THREAD_ATTR_DETACH) {
DequeueActive(thread);
thread->state = 0;
} else {
thread->state = OS_THREAD_STATE_MORIBUND;
}
OSWakeupThread(&thread->queueJoin);
sActiveThreadCount--;
}
void OSDetachThread(OSThread* thread) {
if (!thread) return;
thread->attr |= OS_THREAD_ATTR_DETACH;
if (thread->state == OS_THREAD_STATE_MORIBUND) {
DequeueActive(thread);
thread->state = 0;
}
OSWakeupThread(&thread->queueJoin);
}
int OSJoinThread(OSThread* thread, void* val) {
if (!thread) return 0;
if (!(thread->attr & OS_THREAD_ATTR_DETACH) &&
thread->state != OS_THREAD_STATE_MORIBUND &&
thread->queueJoin.head == nullptr) {
OSSleepThread(&thread->queueJoin);
}
if (thread->state == OS_THREAD_STATE_MORIBUND) {
if (val) {
*(s32*)val = (s32)(intptr_t)thread->val;
}
DequeueActive(thread);
thread->state = 0;
return 1;
}
return 0;
}
// ============================================================================
// Yield / Terminated / Active
// ============================================================================
void OSYieldThread(void) {
std::this_thread::yield();
}
BOOL OSIsThreadSuspended(OSThread* thread) {
return (thread && thread->suspend > 0) ? TRUE : FALSE;
}
BOOL OSIsThreadTerminated(OSThread* thread) {
if (!thread) return TRUE;
return (thread->state == OS_THREAD_STATE_MORIBUND || thread->state == 0) ? TRUE : FALSE;
}
s32 OSCheckActiveThreads(void) {
return sActiveThreadCount.load();
}
// ============================================================================
// Priority
// ============================================================================
int OSSetThreadPriority(OSThread* thread, OSPriority priority) {
if (!thread) return 0;
if (priority < OS_PRIORITY_MIN || priority > OS_PRIORITY_MAX) return 0;
thread->base = priority;
thread->priority = priority;
return 1;
}
s32 OSGetThreadPriority(OSThread* thread) {
if (!thread) return 16;
return thread->base;
}
// ============================================================================
// Switch Thread Callback
// ============================================================================
OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback callback) {
OSSwitchThreadCallback prev = sSwitchThreadCallback;
sSwitchThreadCallback = callback;
return prev;
}
// ============================================================================
// Scheduler (atomic counter, no real effect with native OS threads)
// ============================================================================
s32 OSDisableScheduler(void) {
return sSchedulerSuspendCount.fetch_add(1);
}
s32 OSEnableScheduler(void) {
return sSchedulerSuspendCount.fetch_sub(1);
}
// ============================================================================
// Interrupts (global recursive mutex for mutual exclusion)
// ============================================================================
BOOL OSDisableInterrupts(void) {
GetInterruptMutex().lock();
sInterruptLockCount++;
return (BOOL)(sInterruptLockCount > 1); // TRUE if was already locked
}
BOOL OSRestoreInterrupts(BOOL level) {
if (sInterruptLockCount > 0) {
sInterruptLockCount--;
GetInterruptMutex().unlock();
}
return level;
}
BOOL OSEnableInterrupts(void) {
if (sInterruptLockCount > 0) {
sInterruptLockCount--;
GetInterruptMutex().unlock();
}
return FALSE;
}
// ============================================================================
// Idle function (stub on PC)
// ============================================================================
OSThread* OSSetIdleFunction(OSIdleFunction idleFunction, void* param, void* stack, u32 stackSize) {
return nullptr;
}
OSThread* OSGetIdleFunction(void) {
return nullptr;
}
// ============================================================================
// Thread-specific storage
// ============================================================================
void OSSetThreadSpecific(s32 index, void* ptr) {
OSThread* thread = OSGetCurrentThread();
if (thread && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
thread->specific[index] = ptr;
}
}
void* OSGetThreadSpecific(s32 index) {
OSThread* thread = OSGetCurrentThread();
if (thread && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
return thread->specific[index];
}
return nullptr;
}
// ============================================================================
// Clear stack (minimal implementation)
// ============================================================================
void OSClearStack(u8 val) {
// On PC we don't clear the stack - it's managed by the OS
}
// ============================================================================
// Internal functions used by OSMutex
// ============================================================================
s32 __OSGetEffectivePriority(OSThread* thread) {
// On PC with native threads, priority inversion handling is simplified.
// Just return the base priority.
return thread ? thread->base : 16;
}
void __OSPromoteThread(OSThread* thread, s32 priority) {
// Simplified: no real priority inheritance on PC
if (thread && priority < thread->priority) {
thread->priority = priority;
}
}
void __OSReschedule(void) {
// With native OS threads, rescheduling is handled by the OS.
// Nothing to do here.
}
// ============================================================================
// Interrupt handler registration (stub)
// ============================================================================
__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt,
__OSInterruptHandler handler) {
return nullptr;
}
OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask mask) {
return 0;
}
#ifdef __cplusplus
}
#endif