Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 0 additions & 50 deletions Core/GameEngine/Include/Common/GameAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,55 +383,5 @@ class AudioManager : public SubsystemInterface
Bool m_disallowSpeech : 1;
};

// TheSuperHackers @feature helmutbuhler 17/05/2025
// AudioManager that does nothing. Used for Headless Mode.
class AudioManagerDummy : public AudioManager
{
#if defined(RTS_DEBUG)
virtual void audioDebugDisplay(DebugDisplayInterface* dd, void* userData, FILE* fp) {}
#endif
virtual void stopAudio(AudioAffect which) {}
virtual void pauseAudio(AudioAffect which) {}
virtual void resumeAudio(AudioAffect which) {}
virtual void pauseAmbient(Bool shouldPause) {}
virtual void killAudioEventImmediately(AudioHandle audioEvent) {}
virtual void nextMusicTrack() {}
virtual void prevMusicTrack() {}
virtual Bool isMusicPlaying() const { return false; }
virtual Bool hasMusicTrackCompleted(const AsciiString& trackName, Int numberOfTimes) const { return false; }
virtual AsciiString getMusicTrackName() const { return ""; }
virtual void openDevice() {}
virtual void closeDevice() {}
virtual void* getDevice() { return nullptr; }
virtual void notifyOfAudioCompletion(UnsignedInt audioCompleted, UnsignedInt flags) {}
virtual UnsignedInt getProviderCount() const { return 0; };
virtual AsciiString getProviderName(UnsignedInt providerNum) const { return ""; }
virtual UnsignedInt getProviderIndex(AsciiString providerName) const { return 0; }
virtual void selectProvider(UnsignedInt providerNdx) {}
virtual void unselectProvider() {}
virtual UnsignedInt getSelectedProvider() const { return 0; }
virtual void setSpeakerType(UnsignedInt speakerType) {}
virtual UnsignedInt getSpeakerType() { return 0; }
virtual UnsignedInt getNum2DSamples() const { return 0; }
virtual UnsignedInt getNum3DSamples() const { return 0; }
virtual UnsignedInt getNumStreams() const { return 0; }
virtual Bool doesViolateLimit(AudioEventRTS* event) const { return false; }
virtual Bool isPlayingLowerPriority(AudioEventRTS* event) const { return false; }
virtual Bool isPlayingAlready(AudioEventRTS* event) const { return false; }
virtual Bool isObjectPlayingVoice(UnsignedInt objID) const { return false; }
virtual void adjustVolumeOfPlayingAudio(AsciiString eventName, Real newVolume) {}
virtual void removePlayingAudio(AsciiString eventName) {}
virtual void removeAllDisabledAudio() {}
virtual Bool has3DSensitiveStreamsPlaying() const { return false; }
virtual void* getHandleForBink() { return nullptr; }
virtual void releaseHandleForBink() {}
virtual void friend_forcePlayAudioEventRTS(const AudioEventRTS* eventToPlay) {}
virtual void setPreferredProvider(AsciiString providerNdx) {}
virtual void setPreferredSpeaker(AsciiString speakerType) {}
virtual Real getFileLengthMS(AsciiString strToLoad) const { return -1; }
virtual void closeAnySamplesUsingFile(const void* fileToClose) {}
virtual void setDeviceListenerPosition() {}
};


extern AudioManager *TheAudio;
50 changes: 50 additions & 0 deletions Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,53 @@ class MilesAudioManager : public AudioManager

};

// TheSuperHackers @feature helmutbuhler 17/05/2025 AudioManager that does almost nothing. Used for Headless Mode.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Useful for headless mode"

// @bugfix Caball009 16/02/2026 Scripts may require the actual audio file length to function properly.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps clarify that this is CRC relevant

// The Miles AudioManager handles the device opening / closure, so that getFileLengthMS can function as intended.
class MilesAudioManagerDummy : public MilesAudioManager
{
#if defined(RTS_DEBUG)
virtual void audioDebugDisplay(DebugDisplayInterface* dd, void* userData, FILE* fp) {}
#endif
virtual void stopAudio(AudioAffect which) {}
virtual void pauseAudio(AudioAffect which) {}
virtual void resumeAudio(AudioAffect which) {}
virtual void pauseAmbient(Bool shouldPause) {}
virtual void killAudioEventImmediately(AudioHandle audioEvent) {}
virtual void nextMusicTrack() {}
virtual void prevMusicTrack() {}
virtual Bool isMusicPlaying() const { return false; }
virtual Bool hasMusicTrackCompleted(const AsciiString& trackName, Int numberOfTimes) const { return false; }
virtual AsciiString getMusicTrackName() const { return ""; }
//virtual void openDevice() {}
//virtual void closeDevice() {}
//virtual void* getDevice() { return nullptr; }
Comment on lines +351 to +353
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code. The existing comment at line 335 already explains why these methods aren't overridden.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h
Line: 351-353

Comment:
Remove commented-out code. The existing comment at line 335 already explains why these methods aren't overridden.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's value in providing a complete implementation of AudioManager. The functions that are commented out show clearly, more so than the comment, which functions are not overridden for this dummy implementation.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point. Commented-out method signatures can serve as inline documentation showing what's intentionally not overridden, especially in a class that overrides most other virtual methods.

However, this approach has a trade-off: it creates ambiguity about whether the code is temporarily disabled or intentionally documented. A clearer alternative would be to add these method names to the existing comment at line 335, making it explicit which methods are intentionally not overridden without leaving commented code.

For example:

// Methods intentionally not overridden: openDevice(), closeDevice(), getDevice()

This gives you the same clarity without the "is this dead code?" question. But if you prefer the visual clarity of seeing the signatures, keeping them commented is also reasonable—just be aware that most linters and style guides flag commented-out code as a smell.

Your call on which approach better serves future maintainers.

virtual void notifyOfAudioCompletion(UnsignedInt audioCompleted, UnsignedInt flags) {}
virtual UnsignedInt getProviderCount() const { return 0; };
virtual AsciiString getProviderName(UnsignedInt providerNum) const { return ""; }
virtual UnsignedInt getProviderIndex(AsciiString providerName) const { return 0; }
virtual void selectProvider(UnsignedInt providerNdx) {}
virtual void unselectProvider() {}
virtual UnsignedInt getSelectedProvider() const { return 0; }
virtual void setSpeakerType(UnsignedInt speakerType) {}
virtual UnsignedInt getSpeakerType() { return 0; }
virtual UnsignedInt getNum2DSamples() const { return 0; }
virtual UnsignedInt getNum3DSamples() const { return 0; }
virtual UnsignedInt getNumStreams() const { return 0; }
virtual Bool doesViolateLimit(AudioEventRTS* event) const { return false; }
virtual Bool isPlayingLowerPriority(AudioEventRTS* event) const { return false; }
virtual Bool isPlayingAlready(AudioEventRTS* event) const { return false; }
virtual Bool isObjectPlayingVoice(UnsignedInt objID) const { return false; }
virtual void adjustVolumeOfPlayingAudio(AsciiString eventName, Real newVolume) {}
virtual void removePlayingAudio(AsciiString eventName) {}
virtual void removeAllDisabledAudio() {}
virtual Bool has3DSensitiveStreamsPlaying() const { return false; }
virtual void* getHandleForBink() { return nullptr; }
virtual void releaseHandleForBink() {}
virtual void friend_forcePlayAudioEventRTS(const AudioEventRTS* eventToPlay) {}
virtual void setPreferredProvider(AsciiString providerNdx) {}
virtual void setPreferredSpeaker(AsciiString speakerType) {}
//virtual Real getFileLengthMS(AsciiString strToLoad) const { return 0.0f; }
virtual void closeAnySamplesUsingFile(const void* fileToClose) {}
virtual void setDeviceListenerPosition() {}
};
2 changes: 1 addition & 1 deletion GeneralsMD/Code/GameEngine/Include/Common/GameEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class GameEngine : public SubsystemInterface
virtual Radar *createRadar() = 0; ///< Factory for radar
virtual WebBrowser *createWebBrowser() = 0; ///< Factory for embedded browser
virtual ParticleSystemManager* createParticleSystemManager() = 0;
virtual AudioManager *createAudioManager() = 0; ///< Factory for Audio Manager
virtual AudioManager *createAudioManager(Bool headless) = 0; ///< Factory for Audio Manager

Real m_logicTimeAccumulator; ///< Frame time accumulated towards submitting a new logic frame

Expand Down
2 changes: 1 addition & 1 deletion GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ void GameEngine::init()
startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
#endif/////////////////////////////////////////////////////////////////////////////////////////////
initSubsystem(TheAudio,"TheAudio", TheGlobalData->m_headless ? NEW AudioManagerDummy : createAudioManager(), nullptr);
initSubsystem(TheAudio,"TheAudio", createAudioManager(TheGlobalData->m_headless), nullptr);
if (!TheAudio->isMusicAlreadyLoaded())
setQuitting(TRUE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Win32GameEngine : public GameEngine
virtual NetworkInterface *createNetwork(); ///< Factory for the network
virtual Radar *createRadar(); ///< Factory for radar
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps mirror the implemention for createRadar?

It currently also does TheGlobalData->m_headless ? NEW RadarDummy : createRadar()

virtual WebBrowser *createWebBrowser(); ///< Factory for embedded browser
virtual AudioManager *createAudioManager(); ///< Factory for audio device
virtual AudioManager *createAudioManager(Bool headless); ///< Factory for audio device
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe do Bool dummy ? Because it may not just be headless that want's to use a dummy in the future, aka the Dummy class should not care in what context it is used.

virtual ParticleSystemManager* createParticleSystemManager();


Expand All @@ -98,4 +98,4 @@ inline ParticleSystemManager* Win32GameEngine::createParticleSystemManager() { r
inline NetworkInterface *Win32GameEngine::createNetwork() { return NetworkInterface::createNetwork(); }
inline Radar *Win32GameEngine::createRadar() { return NEW W3DRadar; }
inline WebBrowser *Win32GameEngine::createWebBrowser() { return NEW CComObject<W3DWebBrowser>; }
inline AudioManager *Win32GameEngine::createAudioManager() { return NEW MilesAudioManager; }
inline AudioManager *Win32GameEngine::createAudioManager(Bool headless) { return headless ? NEW MilesAudioManagerDummy : NEW MilesAudioManager; }
Loading