You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2554 lines
73 KiB
2554 lines
73 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#pragma warning(disable: 4284) |
|
#include "HeadSpin.h" |
|
#include "hsTypes.h" |
|
#include "hsWindowHndl.h" |
|
#include "plClient.h" |
|
#include "hsStream.h" |
|
#include "../plResMgr/plResManager.h" |
|
#include "../plResMgr/plKeyFinder.h" |
|
#include "../pnKeyedObject/plKey.h" |
|
#include "../pnKeyedObject/plFixedKey.h" |
|
#include "../pnMessage/plRefMsg.h" |
|
#include "../pnSceneObject/plSceneObject.h" |
|
#include "../pnSceneObject/plCoordinateInterface.h" |
|
#include "../plScene/plSceneNode.h" |
|
#include "../pnMessage/plTimeMsg.h" |
|
#include "../pnMessage/plClientMsg.h" |
|
#include "../pfCamera/plVirtualCamNeu.h" |
|
#include "hsTimer.h" |
|
#include "../plPipeline/hsG3DDeviceSelector.h" |
|
#include "../plFile/plEncryptedStream.h" |
|
#include "../plFile/plFileUtils.h" |
|
#include "../plInputCore/plInputManager.h" |
|
#include "../plInputCore/plInputInterfaceMgr.h" |
|
#include "../plInputCore/plInputDevice.h" |
|
#include "../plPhysX/plSimulationMgr.h" |
|
#include "../plNetClient/plNetClientMgr.h" |
|
#include "../plAvatar/plAvatarMgr.h" |
|
#include "../plScene/plRelevanceMgr.h" |
|
#include "../pnTimer/plTimerCallbackManager.h" |
|
#include "../pfAudio/plListener.h" |
|
#include "../pnMessage/plCmdIfaceModMsg.h" |
|
#include "../plMessage/plRoomLoadNotifyMsg.h" |
|
#include "../pnMessage/plPlayerPageMsg.h" |
|
#include "../pnMessage/plCameraMsg.h" |
|
#include "../plMessage/plTransitionMsg.h" |
|
#include "../plMessage/plLinkToAgeMsg.h" |
|
#include "../plMessage/plPreloaderMsg.h" |
|
#include "../plMessage/plNetCommMsgs.h" |
|
#include "../plMessage/plAgeLoadedMsg.h" |
|
|
|
#include "../pfConsole/pfConsoleEngine.h" |
|
#include "../pfConsole/pfConsole.h" |
|
#include "../pfConsole/pfConsoleDirSrc.h" |
|
#include "../plScene/plPageTreeMgr.h" |
|
#include "../plScene/plVisMgr.h" |
|
#include "../plFile/hsFiles.h" |
|
|
|
#include "../pfKI/pfKI.h" |
|
|
|
#include "../plAudio/plAudioSystem.h" |
|
#include "../plAudio/plAudioCaps.h" |
|
|
|
#include "../plStatGather/plProfileManagerFull.h" |
|
|
|
#include "plPipeline.h" |
|
#include "../plPipeline/plPipelineCreate.h" |
|
#include "../plPipeline/plPipeDebugFlags.h" |
|
#include "../plPipeline/plTransitionMgr.h" |
|
#include "../plPipeline/plCaptureRender.h" |
|
#include "../plPipeline/plDynamicEnvMap.h" |
|
#include "../plNetClient/plLinkEffectsMgr.h" |
|
#include "../plAvatar/plAvatarClothing.h" |
|
#include "../plAvatar/plArmatureMod.h" |
|
#include "../pnMessage/plProxyDrawMsg.h" |
|
|
|
#include "../plScene/plRenderRequest.h" |
|
#include "../plDrawable/plAccessGeometry.h" |
|
#include "plPipeResReq.h" |
|
#include "../plDrawable/plVisLOSMgr.h" |
|
|
|
#include "../plGImage/plBitmap.h" |
|
|
|
#include "../plStatusLog/plStatusLog.h" |
|
#include "../plProgressMgr/plProgressMgr.h" |
|
#include "../plPipeline/plDTProgressMgr.h" |
|
#include "../plPipeline/plBinkPlayer.h" |
|
#include "../plMessage/plMovieMsg.h" |
|
|
|
#include "../plSDL/plSDL.h" |
|
|
|
#include "../pnDispatch/plDispatch.h" |
|
#include "../pnDispatch/plDispatchLogBase.h" |
|
#include "../pfGameGUIMgr/pfGameGUIMgr.h" |
|
#include "../pfPython/cyMisc.h" |
|
#include "../plMessage/plInputEventMsg.h" |
|
#include "../plMessage/plRenderRequestMsg.h" |
|
#include "../pnMessage/plEventCallbackMsg.h" |
|
#include "../plModifier/plSimpleModifier.h" |
|
#include "plAudible.h" |
|
#include "../plMessage/plAnimCmdMsg.h" |
|
#include "../pnMessage/plSoundMsg.h" |
|
#include "../pnMessage/plAudioSysMsg.h" |
|
#include "../plMessage/plRenderMsg.h" |
|
#include "../plAgeLoader/plResPatcher.h" |
|
#include "../pfPython/cyPythonInterface.h" |
|
#include "../plUnifiedTime/plClientUnifiedTime.h" |
|
#include "../pfAnimation/plAnimDebugList.h" |
|
#include "../pfGameGUIMgr/pfGUICtrlGenerator.h" |
|
|
|
#include "../plGImage/plWinFontCache.h" |
|
#include "../plGImage/plFontCache.h" |
|
|
|
#include "../pfJournalBook/pfJournalBook.h" |
|
|
|
#include "../plAvatar/plAGAnimInstance.h" |
|
#include "../plAgeLoader/plAgeLoader.h" |
|
#include "../plClientKey/plClientKey.h" |
|
|
|
#include "../CoreLib/plQuality.h" |
|
#include "../plGLight/plShadowCaster.h" |
|
|
|
#include "../plNetClient/plNetLinkingMgr.h" |
|
#include "../plNetCommon/plNetCommonConstants.h" |
|
#include "../plNetGameLib/plNetGameLib.h" |
|
|
|
#include "../pfSecurePreloader/pfSecurePreloader.h" |
|
#include "../pfLocalizationMgr/pfLocalizationMgr.h" |
|
|
|
#include "../pfCsrSrv/pfCsrSrv.h" |
|
|
|
#include "plTweak.h" |
|
|
|
#define MSG_LOADING_BAR |
|
|
|
// static hsVector3 gAbsDown(0,0,-hsScalar1); |
|
|
|
static plDispatchBase* gDisp = nil; |
|
static plTimerCallbackManager* gTimerMgr = nil; |
|
static plAudioSystem* gAudio = nil; |
|
|
|
hsBool plClient::fDelayMS = false; |
|
|
|
plClient* plClient::fInstance=nil; |
|
|
|
static hsTArray<HMODULE> fLoadedDLLs; |
|
|
|
plClient::plClient() |
|
: fPipeline(nil), |
|
fDone(false), |
|
fQuitIntro(false), |
|
fWindowHndl(nil), |
|
fInputManager(nil), |
|
fConsole(nil), |
|
fCurrentNode(nil), |
|
fNewCamera(nil), |
|
fpAuxInitDir(nil), |
|
fTransitionMgr(nil), |
|
fLinkEffectsMgr(nil), |
|
fProgressBar(nil), |
|
fGameGUIMgr(nil), |
|
fKIGUIGlue(nil), |
|
fWindowActive(false), |
|
fAnimDebugList(nil), |
|
fClampCap(-1), |
|
fQuality(0), |
|
fPageMgr(nil), |
|
fFontCache(nil), |
|
fHoldLoadRequests(false), |
|
fNumLoadingRooms(0), |
|
fNumPostLoadMsgs(0), |
|
fPostLoadMsgInc(0.f), |
|
fPatchGlobalAges(false) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
bPythonDebugConnected = false; |
|
#endif |
|
|
|
hsStatusMessage("Constructing client\n"); |
|
plClient::SetInstance(this); |
|
// gNextRoom[0] = '\0'; |
|
|
|
// Setup the timer. These can be overriden with console commands. |
|
hsTimer::SetRealTime(true); |
|
#ifdef HS_DEBUGGING |
|
// hsTimer::SetRealTime(false); |
|
hsTimer::SetTimeClamp(0.1f); |
|
#else // HS_DEBUGGING |
|
// hsTimer::SetRealTime(true); |
|
hsTimer::SetTimeClamp(0); |
|
#endif // HS_DEBUGGING |
|
|
|
IDetectAudioVideoSettings(); // need to do this before the console is created |
|
|
|
/// allow console commands to start working early |
|
// Create the console engine |
|
fConsoleEngine = TRACKED_NEW pfConsoleEngine(); |
|
|
|
// create network mgr before console runs |
|
plNetClientMgr::SetInstance(TRACKED_NEW plNetClientMgr); |
|
plAgeLoader::SetInstance(TRACKED_NEW plAgeLoader); |
|
|
|
// Use it to parse the init directory |
|
wchar initFolder[MAX_PATH]; |
|
PathGetInitDirectory(initFolder, arrsize(initFolder)); |
|
pfConsoleDirSrc dirSrc( fConsoleEngine, initFolder, L"*.ini" ); |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// internal builds also parse the local init folder |
|
dirSrc.ParseDirectory( L"init", L"*.ini" ); |
|
#endif |
|
|
|
/// End of console stuff |
|
} |
|
|
|
plClient::~plClient() |
|
{ |
|
hsStatusMessage("Destructing client\n"); |
|
|
|
plClient::SetInstance( nil ); |
|
|
|
delete fPageMgr; |
|
delete [] fpAuxInitDir; |
|
} |
|
|
|
#include "../plGImage/plAVIWriter.h" |
|
#include "../pfCharacter/pfMarkerMgr.h" |
|
|
|
hsBool plClient::Shutdown() |
|
{ |
|
plSynchEnabler ps(false); // disable dirty state tracking during shutdown |
|
delete fProgressBar; |
|
|
|
CsrSrvShutdown(); |
|
|
|
// Just in case, clear this out (trying to fix a crash bug where this is still active at shutdown) |
|
plDispatch::SetMsgRecieveCallback(nil); |
|
|
|
// Let the resmanager know we're going to be shutting down. |
|
hsgResMgr::ResMgr()->BeginShutdown(); |
|
|
|
// Must kill off all movies before shutting down audio. |
|
IKillMovies(); |
|
|
|
plgAudioSys::Activate(false); |
|
plBinkPlayer::DeInit(); |
|
// |
|
// Get any proxies to commit suicide. |
|
plProxyDrawMsg* nuke = TRACKED_NEW plProxyDrawMsg(plProxyDrawMsg::kAllTypes |
|
| plProxyDrawMsg::kDestroy); |
|
plgDispatch::MsgSend(nuke); |
|
|
|
if (plAVIWriter::IsInitialized()) |
|
plAVIWriter::Instance().Shutdown(); |
|
|
|
hsStatusMessage( "Shutting down client...\n" ); |
|
|
|
// First, before anybody else goes away, write out our key mappings |
|
if( plInputInterfaceMgr::GetInstance() ) |
|
plInputInterfaceMgr::GetInstance()->WriteKeyMap(); |
|
|
|
// tell Python that its ok to shutdown |
|
PythonInterface::WeAreInShutdown(); |
|
|
|
// Shutdown the journalBook API |
|
pfJournalBook::SingletonShutdown(); |
|
|
|
/// Take down the KI |
|
pfGameGUIMgr *mgr = pfGameGUIMgr::GetInstance(); |
|
if( mgr ) |
|
mgr->UnloadDialog( "KIBlackBar" ); // unload the blackbar which will bootstrap in the rest of the KI dialogs |
|
|
|
// Take down our GUI control generator |
|
pfGUICtrlGenerator::Instance().Shutdown(); |
|
|
|
if (plNetClientMgr::GetInstance()) |
|
{ |
|
plNetClientMgr::GetInstance()->Shutdown(); |
|
plNetClientMgr::GetInstance()->UnRegisterAs(kNetClientMgr_KEY); // deletes NetClientMgr instance |
|
plNetClientMgr::SetInstance(nil); |
|
} |
|
|
|
if (plAgeLoader::GetInstance()) |
|
{ |
|
plAgeLoader::GetInstance()->Shutdown(); |
|
plAgeLoader::GetInstance()->UnRegisterAs(kAgeLoader_KEY); // deletes instance |
|
plAgeLoader::SetInstance(nil); |
|
} |
|
|
|
if (pfSecurePreloader::IsInstanced()) |
|
{ |
|
pfSecurePreloader::GetInstance()->Shutdown(); |
|
// pfSecurePreloader handles its own fixed key unregistration |
|
} |
|
|
|
if (fInputManager) |
|
{ |
|
fInputManager->UnRegisterAs(kInput_KEY); |
|
fInputManager = nil; |
|
} |
|
|
|
if( fGameGUIMgr != nil ) |
|
{ |
|
fGameGUIMgr->UnRegisterAs( kGameGUIMgr_KEY ); |
|
fGameGUIMgr = nil; |
|
} |
|
|
|
for (int i = 0; i < fRooms.Count(); i++) |
|
{ |
|
plSceneNode *sn = fRooms[i].fNode; |
|
GetKey()->Release(sn->GetKey()); |
|
} |
|
fRooms.Reset(); |
|
fRoomsLoading.clear(); |
|
|
|
// Shutdown plNetClientMgr |
|
|
|
plAccessGeometry::DeInit(); |
|
|
|
delete fPipeline; |
|
fPipeline = nil; |
|
|
|
if (plSimulationMgr::GetInstance()) |
|
plSimulationMgr::Shutdown(); |
|
plAvatarMgr::ShutDown(); |
|
plRelevanceMgr::DeInit(); |
|
|
|
if (fPageMgr) |
|
fPageMgr->Reset(); |
|
|
|
if( fKIGUIGlue != nil ) |
|
{ |
|
fKIGUIGlue->UnRegisterAs( kKIGUIGlue_KEY ); |
|
fKIGUIGlue = nil; |
|
} |
|
|
|
if( fTransitionMgr != nil ) |
|
{ |
|
fTransitionMgr->UnRegisterAs( kTransitionMgr_KEY ); |
|
fTransitionMgr = nil; |
|
} |
|
|
|
delete fConsoleEngine; |
|
fConsoleEngine = nil; |
|
|
|
if (fLinkEffectsMgr) |
|
{ |
|
fLinkEffectsMgr->UnRegisterAs( kLinkEffectsMgr_KEY); |
|
fLinkEffectsMgr=nil; |
|
} |
|
|
|
plClothingMgr::DeInit(); |
|
|
|
if( fFontCache != nil ) |
|
{ |
|
fFontCache->UnRegisterAs( kFontCache_KEY ); |
|
fFontCache = nil; |
|
} |
|
|
|
pfMarkerMgr::Shutdown(); |
|
|
|
delete fAnimDebugList; |
|
|
|
//#ifndef PLASMA_EXTERNAL_RELEASE |
|
if( fConsole != nil ) |
|
{ |
|
// UnRegisterAs destroys the object for us |
|
fConsole->UnRegisterAs( kConsoleObject_KEY ); |
|
fConsole = nil; |
|
} |
|
//#endif |
|
|
|
PythonInterface::finiPython(); |
|
|
|
if (fNewCamera) |
|
fNewCamera->UnRegisterAs( kVirtualCamera1_KEY ); |
|
|
|
// mark the listener for death. |
|
// there's no need to keep this around... |
|
plUoid lu(kListenerMod_KEY); |
|
plKey pLKey = hsgResMgr::ResMgr()->FindKey(lu); |
|
if (pLKey) |
|
{ |
|
plListener* pLMod = plListener::ConvertNoRef(pLKey->GetObjectPtr()); |
|
if (pLMod) |
|
pLMod->UnRegisterAs(kListenerMod_KEY); |
|
} |
|
|
|
plgAudioSys::Shutdown(); |
|
|
|
if (pfLocalizationMgr::InstanceValid()) |
|
pfLocalizationMgr::Shutdown(); |
|
|
|
ShutdownDLLs(); |
|
|
|
plVisLOSMgr::DeInit(); |
|
|
|
delete fPageMgr; |
|
fPageMgr = nil; |
|
plGlobalVisMgr::DeInit(); |
|
|
|
#ifdef TRACK_AG_ALLOCS |
|
DumpAGAllocs(); |
|
#endif // TRACK_AG_ALLOCS |
|
|
|
// This will destruct the client. Do it last. |
|
UnRegisterAs(kClient_KEY); |
|
|
|
|
|
return false; |
|
} |
|
|
|
void plClient::InitAuxInits() |
|
{ |
|
// Use another init directory specified in Command line Arg -i |
|
if (fpAuxInitDir) |
|
pfConsoleDirSrc dirSrc( fConsoleEngine, fpAuxInitDir, "*.ini" ); |
|
} |
|
|
|
void plClient::InitInputs() |
|
{ |
|
hsStatusMessage("InitInputs client\n"); |
|
fInputManager = TRACKED_NEW plInputManager( fWindowHndl ); |
|
fInputManager->CreateInterfaceMod(fPipeline); |
|
fInputManager->RegisterAs( kInput_KEY ); |
|
plgDispatch::Dispatch()->RegisterForExactType(plIMouseXEventMsg::Index(), fInputManager->GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plIMouseYEventMsg::Index(), fInputManager->GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plIMouseBEventMsg::Index(), fInputManager->GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), fInputManager->GetKey()); |
|
plInputDevice* pKeyboard = TRACKED_NEW plKeyboardDevice(); |
|
fInputManager->AddInputDevice(pKeyboard); |
|
|
|
plInputDevice* pMouse = TRACKED_NEW plMouseDevice(); |
|
fInputManager->AddInputDevice(pMouse); |
|
|
|
if( fWindowActive ) |
|
fInputManager->Activate( true ); |
|
} |
|
|
|
void plClient::ISetGraphicsDefaults() |
|
{ |
|
// couldn't find display mode set defaults write to ini file |
|
wchar graphicsIniFile[MAX_PATH]; |
|
PathGetInitDirectory(graphicsIniFile, arrsize(graphicsIniFile)); |
|
PathAddFilename(graphicsIniFile, graphicsIniFile, L"graphics.ini", arrsize(graphicsIniFile)); |
|
IWriteDefaultGraphicsSettings(graphicsIniFile); |
|
plPipeline::fInitialPipeParams.Windowed = plPipeline::fDefaultPipeParams.Windowed; |
|
plPipeline::fInitialPipeParams.AntiAliasingAmount = plPipeline::fDefaultPipeParams.AntiAliasingAmount; |
|
plPipeline::fInitialPipeParams.AnisotropicLevel = plPipeline::fDefaultPipeParams.AnisotropicLevel; |
|
plPipeline::fInitialPipeParams.TextureQuality = plPipeline::fDefaultPipeParams.TextureQuality; |
|
plPipeline::fInitialPipeParams.VSync = plPipeline::fDefaultPipeParams.VSync; |
|
plShadowCaster::EnableShadowCast(plPipeline::fDefaultPipeParams.Shadows ? true : false); |
|
plQuality::SetQuality(plPipeline::fDefaultPipeParams.VideoQuality); |
|
if( (fClampCap >= 0) && (fClampCap < plQuality::GetCapability()) ) |
|
plQuality::SetCapability(fClampCap); |
|
plDynamicCamMap::SetEnabled(plPipeline::fDefaultPipeParams.PlanarReflections ? true : false); |
|
} |
|
|
|
hsBool plClient::InitPipeline() |
|
{ |
|
hsStatusMessage("InitPipeline client\n"); |
|
HWND hWnd = fWindowHndl; |
|
|
|
hsG3DDeviceModeRecord dmr; |
|
hsG3DDeviceSelector devSel; |
|
devSel.Enumerate(hWnd); |
|
devSel.RemoveUnusableDevModes(true); |
|
|
|
if (!devSel.GetDefault(&dmr)) |
|
{ |
|
hsMessageBox("No suitable rendering devices found.","Plasma", hsMessageBoxNormal, hsMessageBoxIconError); |
|
return true; |
|
} |
|
|
|
hsG3DDeviceRecord *rec = (hsG3DDeviceRecord *)dmr.GetDevice(); |
|
int res = -1; |
|
|
|
if(!plPipeline::fInitialPipeParams.Windowed) |
|
{ |
|
// find our resolution if we're not in windowed mode |
|
for ( int i = 0; i < rec->GetModes().GetCount(); i++ ) |
|
{ |
|
hsG3DDeviceMode *mode = rec->GetMode(i); |
|
if ((mode->GetWidth() == plPipeline::fInitialPipeParams.Width) && |
|
(mode->GetHeight() == plPipeline::fInitialPipeParams.Height) && |
|
(mode->GetColorDepth() == plPipeline::fInitialPipeParams.ColorDepth)) |
|
{ |
|
res = i; |
|
break; |
|
} |
|
} |
|
if(res != -1) |
|
{ |
|
// found it set it as the current mode. |
|
dmr = hsG3DDeviceModeRecord(*rec, *rec->GetMode(res)); |
|
} |
|
else |
|
{ |
|
ISetGraphicsDefaults(); |
|
} |
|
} |
|
|
|
if(plPipeline::fInitialPipeParams.TextureQuality == -1) |
|
{ |
|
plPipeline::fInitialPipeParams.TextureQuality = dmr.GetDevice()->GetCap(hsG3DDeviceSelector::kCapsPixelShader) ? 2 : 1; |
|
} |
|
else |
|
{ |
|
// clamp value to range |
|
if(plPipeline::fInitialPipeParams.TextureQuality > 2) plPipeline::fInitialPipeParams.TextureQuality = 2; |
|
if(plPipeline::fInitialPipeParams.TextureQuality < 0) plPipeline::fInitialPipeParams.TextureQuality = 0; |
|
plBitmap::SetGlobalLevelChopCount(2 - plPipeline::fInitialPipeParams.TextureQuality); |
|
} |
|
|
|
plPipeline *pipe = plPipelineCreate::CreatePipeline( hWnd, &dmr ); |
|
if( pipe->GetErrorString() != nil ) |
|
{ |
|
ISetGraphicsDefaults(); |
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
hsMessageBox("There was an error initializing the video card.\nSetting defaults.", "Error", hsMessageBoxNormal); |
|
#else |
|
hsMessageBox( pipe->GetErrorString(), "Error creating pipeline", hsMessageBoxNormal ); |
|
#endif |
|
delete pipe; |
|
devSel.GetDefault(&dmr); |
|
pipe = plPipelineCreate::CreatePipeline( hWnd, &dmr ); |
|
if(pipe->GetErrorString() != nil) |
|
{ |
|
// not much else we can do |
|
return true; |
|
} |
|
} |
|
fPipeline = pipe; |
|
|
|
hsVector3 up; |
|
hsPoint3 from, at; |
|
from.Set(0, 0, 10.f); |
|
at.Set(0, 20.f, 10.f); |
|
up.Set(0,0,-1.f); |
|
hsMatrix44 cam; |
|
cam.MakeCamera(&from,&at,&up); |
|
|
|
float yon = 500.0f; |
|
|
|
pipe->SetFOV( 60.f, hsIntToScalar( 60.f * pipe->Height() / pipe->Width() ) ); |
|
pipe->SetDepth( 0.3f, yon ); |
|
|
|
hsMatrix44 id; |
|
id.Reset(); |
|
|
|
pipe->SetWorldToCamera( cam, id ); |
|
pipe->RefreshMatrices(); |
|
|
|
// Do this so we're still black before we show progress bars, but the correct color coming out of 'em |
|
fClearColor.Set( 0.f, 0.f, 0.f, 1.f ); |
|
pipe->SetClear(&fClearColor); |
|
pipe->ClearRenderTarget(); |
|
|
|
plAccessGeometry::Init(pipe); |
|
|
|
if( fPipeline ) |
|
fPipeline->LoadResources(); |
|
|
|
return false; |
|
} |
|
|
|
//============================================================================ |
|
void plClient::SetClearColor( hsColorRGBA &color ) |
|
{ |
|
fClearColor = color; |
|
if( fPipeline != nil ) |
|
{ |
|
fPipeline->SetClear(&fClearColor, nil); |
|
} |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IDispatchMsgReceiveCallback() |
|
{ |
|
if (fInstance->fProgressBar) |
|
fInstance->fProgressBar->Increment(1); |
|
|
|
static char buf[30]; |
|
sprintf(buf, "Msg %d", fInstance->fNumPostLoadMsgs); |
|
fInstance->IIncProgress(fInstance->fPostLoadMsgInc, buf); |
|
|
|
fInstance->fNumPostLoadMsgs++; |
|
} |
|
|
|
|
|
//============================================================================ |
|
hsBool plClient::MsgReceive(plMessage* msg) |
|
{ |
|
if (plGenRefMsg * genRefMsg = plGenRefMsg::ConvertNoRef(msg)) { |
|
// do nothing, we just use the client's key to ref vault image nodes. |
|
return true; |
|
} |
|
|
|
plClientRefMsg* pRefMsg = plClientRefMsg::ConvertNoRef(msg); |
|
if (pRefMsg) |
|
{ |
|
switch(pRefMsg->fType) |
|
{ |
|
case plClientRefMsg::kLoadRoom : |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plStatusLog::AddLineS( "pageouts.log", ".. ClientRefMsg received for room %s", pRefMsg->GetRef() != nil ? pRefMsg->GetRef()->GetKey()->GetUoid().GetObjectName() : "nilref" ); |
|
#endif |
|
|
|
// was it that the room was loaded? |
|
if (hsCheckBits(pRefMsg->GetContext(), plRefMsg::kOnCreate)) |
|
IRoomLoaded(plSceneNode::Convert(pRefMsg->GetRef()), false); |
|
// or was it that the room was unloaded? |
|
else if (hsCheckBits(pRefMsg->GetContext(), plRefMsg::kOnDestroy)) |
|
IRoomUnloaded(plSceneNode::Convert(pRefMsg->GetRef())); |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
else |
|
plStatusLog::AddLineS("pageouts.log", ".. refMsg is UNHANDLED"); |
|
#endif |
|
break; |
|
|
|
case plClientRefMsg::kLoadRoomHold: |
|
if (hsCheckBits(pRefMsg->GetContext(), plRefMsg::kOnCreate)) |
|
IRoomLoaded(plSceneNode::Convert(pRefMsg->GetRef()), true); |
|
break; |
|
|
|
// |
|
// Manually add room. |
|
// Add to pageMgr, but don't load the entire room. |
|
// |
|
case plClientRefMsg::kManualRoom: |
|
{ |
|
if (pRefMsg->GetContext() & plRefMsg::kOnCreate || |
|
pRefMsg->GetContext() & plRefMsg::kOnRequest) |
|
{ |
|
hsBool found=false; |
|
plSceneNode *pNode = plSceneNode::ConvertNoRef(pRefMsg->GetRef()); |
|
int i; |
|
for (i = 0; i < fRooms.Count(); i++) |
|
{ |
|
if (fRooms[i].fNode->GetKey() == pRefMsg->GetSender()) |
|
{ |
|
found=true; |
|
break; |
|
} |
|
} |
|
if (!found) |
|
{ |
|
if (pNode) |
|
{ |
|
fRooms.Append( plRoomRec( pNode, 0 ) ); |
|
fPageMgr->AddNode(pNode); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
plSceneNode* node = plSceneNode::ConvertNoRef(pRefMsg->GetRef()); |
|
if(node) |
|
{ |
|
int i; |
|
for (i = 0; i < fRooms.Count(); i++) |
|
{ |
|
if (fRooms[i].fNode->GetKey() == node->GetKey()) |
|
{ |
|
fRooms.Remove(i); |
|
break; |
|
} |
|
} |
|
fPageMgr->RemoveNode(node); |
|
} |
|
} |
|
} |
|
break; |
|
|
|
} |
|
} |
|
|
|
plClientMsg* pMsg = plClientMsg::ConvertNoRef(msg); |
|
if (pMsg) |
|
{ |
|
switch(pMsg->GetClientMsgFlag()) |
|
{ |
|
case plClientMsg::kQuit: |
|
SetDone(true); |
|
break; |
|
|
|
case plClientMsg::kLoadRoom: |
|
case plClientMsg::kLoadRoomHold: |
|
{ |
|
IQueueRoomLoad(pMsg->GetRoomLocs(), (pMsg->GetClientMsgFlag() == plClientMsg::kLoadRoomHold)); |
|
if (!fHoldLoadRequests) |
|
ILoadNextRoom(); |
|
} |
|
break; |
|
|
|
case plClientMsg::kUnloadRoom: |
|
IUnloadRooms(pMsg->GetRoomLocs()); |
|
break; |
|
|
|
case plClientMsg::kLoadNextRoom: |
|
ILoadNextRoom(); |
|
break; |
|
|
|
// Load optimizations: messages to pre-load and un-load all the keys in a given age |
|
case plClientMsg::kLoadAgeKeys: |
|
{ |
|
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr(); |
|
mgr->LoadAgeKeys( pMsg->GetAgeName() ); |
|
} |
|
break; |
|
|
|
case plClientMsg::kReleaseAgeKeys: |
|
{ |
|
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr(); |
|
mgr->DropAgeKeys( pMsg->GetAgeName() ); |
|
} |
|
break; |
|
|
|
case plClientMsg::kDisableRenderScene: |
|
{ |
|
plClient::GetInstance()->SetFlag( plClient::kFlagDBGDisableRender, true ); |
|
} |
|
break; |
|
case plClientMsg::kEnableRenderScene: |
|
{ |
|
plClient::GetInstance()->SetFlag( plClient::kFlagDBGDisableRender, false ); |
|
} |
|
break; |
|
|
|
case plClientMsg::kResetGraphicsDevice: |
|
{ |
|
ResetDisplayDevice(pMsg->fGraphicsSettings.fWidth, pMsg->fGraphicsSettings.fHeight, pMsg->fGraphicsSettings.fColorDepth, pMsg->fGraphicsSettings.fWindowed, pMsg->fGraphicsSettings.fNumAASamples, pMsg->fGraphicsSettings.fMaxAnisoSamples, pMsg->fGraphicsSettings.fVSync); |
|
} |
|
break; |
|
|
|
case plClientMsg::kSetGraphicsDefaults: |
|
{ |
|
ISetGraphicsDefaults(); |
|
ResetDisplayDevice(plPipeline::fDefaultPipeParams.Width, plPipeline::fDefaultPipeParams.Height, plPipeline::fDefaultPipeParams.ColorDepth, plPipeline::fDefaultPipeParams.Windowed, |
|
plPipeline::fDefaultPipeParams.AntiAliasingAmount, plPipeline::fDefaultPipeParams.AnisotropicLevel, plPipeline::fDefaultPipeParams.VSync, true); |
|
} |
|
break; |
|
|
|
} |
|
return true; |
|
} |
|
plRenderRequestMsg* rendReq = plRenderRequestMsg::ConvertNoRef(msg); |
|
if( rendReq ) |
|
{ |
|
IAddRenderRequest(rendReq->Request()); |
|
return true; |
|
} |
|
plEventCallbackMsg* callback = plEventCallbackMsg::ConvertNoRef(msg); |
|
if( callback ) |
|
{ |
|
char str[256]; |
|
sprintf(str, "Callback event from %s\n", callback->GetSender() |
|
? callback->GetSender()->GetName() |
|
: "Unknown"); |
|
hsStatusMessage(str); |
|
static int gotten = 0; |
|
if( ++gotten > 5 ) |
|
{ |
|
plSimpleModifier* simpMod = plSimpleModifier::ConvertNoRef(callback->GetSender()->ObjectIsLoaded()); |
|
plAudible* aud = plAudible::ConvertNoRef(callback->GetSender()->ObjectIsLoaded()); |
|
if( simpMod ) |
|
{ |
|
plAnimCmdMsg* cmd = TRACKED_NEW plAnimCmdMsg; |
|
cmd->AddReceiver(simpMod->GetKey()); |
|
cmd->SetCmd(plAnimCmdMsg::kRemoveCallbacks); |
|
cmd->AddCallback(callback); |
|
plgDispatch::MsgSend(cmd); |
|
hsRefCnt_SafeUnRef(callback); |
|
} |
|
else if( aud ) |
|
{ |
|
plSoundMsg* cmd = TRACKED_NEW plSoundMsg; |
|
cmd->AddReceiver(aud->GetKey()); |
|
cmd->SetCmd(plSoundMsg::kRemoveCallbacks); |
|
cmd->AddCallback(callback); |
|
plgDispatch::MsgSend(cmd); |
|
hsRefCnt_SafeUnRef(callback); |
|
} |
|
hsStatusMessage("Removed\n"); |
|
gotten = 0; |
|
} |
|
return true; |
|
} |
|
plMovieMsg* mov = plMovieMsg::ConvertNoRef(msg); |
|
if( mov ) |
|
{ |
|
return IHandleMovieMsg(mov); |
|
} |
|
|
|
plLinkEffectsTriggerMsg* linkFX = plLinkEffectsTriggerMsg::ConvertNoRef(msg); |
|
if (linkFX) |
|
{ |
|
if (!linkFX->IsLeavingAge()) |
|
{ |
|
#ifdef MSG_LOADING_BAR |
|
// Temporary stat gathering stuff |
|
#if 0//ndef PLASMA_EXTERNAL_RELEASE |
|
hsUNIXStream s; |
|
s.Open("Messages.txt", "at"); |
|
static bool firstLog = true; |
|
if (firstLog) |
|
{ |
|
firstLog = false; |
|
s.WriteString("------------------------------------\n"); |
|
} |
|
char buf[256]; |
|
sprintf(buf, "%s %d\n", plAgeLoader::GetInstance()->GetCurrAgeFilename(), fNumPostLoadMsgs); |
|
s.WriteString(buf); |
|
s.Close(); |
|
#endif |
|
#endif |
|
} |
|
return true; |
|
} |
|
|
|
//============================================================================ |
|
// plNetCommAuthMsg |
|
//============================================================================ |
|
if (plNetCommAuthMsg * authCommMsg = plNetCommAuthMsg::ConvertNoRef(msg)) { |
|
IHandleNetCommAuthMsg(authCommMsg); |
|
return true; |
|
} |
|
|
|
//============================================================================ |
|
// plPreloaderMsg |
|
//============================================================================ |
|
if (plPreloaderMsg * preloaderMsg = plPreloaderMsg::ConvertNoRef(msg)) { |
|
IHandlePreloaderMsg(preloaderMsg); |
|
return true; |
|
} |
|
|
|
return hsKeyedObject::MsgReceive(msg); |
|
} |
|
|
|
//============================================================================ |
|
hsBool plClient::IHandleMovieMsg(plMovieMsg* mov) |
|
{ |
|
if( !(mov->GetFileName() && *mov->GetFileName()) ) |
|
return true; |
|
|
|
int i; |
|
i = fMovies.GetCount(); |
|
if( !(mov->GetCmd() & plMovieMsg::kMake) ) |
|
{ |
|
for( i = 0; i < fMovies.GetCount(); i++ ) |
|
{ |
|
if( !stricmp(mov->GetFileName(), fMovies[i]->GetFileName()) ) |
|
break; |
|
} |
|
} |
|
if( i == fMovies.GetCount() ) |
|
{ |
|
|
|
fMovies.Append(TRACKED_NEW plBinkPlayer); |
|
fMovies[i]->SetFileName(mov->GetFileName()); |
|
} |
|
|
|
if( mov->GetCmd() & plMovieMsg::kAddCallbacks ) |
|
{ |
|
int j; |
|
for( j = 0; j < mov->GetNumCallbacks(); j++ ) |
|
fMovies[i]->AddCallback(mov->GetCallback(j)); |
|
} |
|
if( mov->GetCmd() & plMovieMsg::kMove ) |
|
fMovies[i]->SetPosition(mov->GetCenter()); |
|
if( mov->GetCmd() & plMovieMsg::kScale ) |
|
fMovies[i]->SetScale(mov->GetScale()); |
|
if( mov->GetCmd() & plMovieMsg::kColorAndOpacity ) |
|
fMovies[i]->SetColor(mov->GetColor()); |
|
if( mov->GetCmd() & plMovieMsg::kColor ) |
|
{ |
|
hsColorRGBA c = fMovies[i]->GetColor(); |
|
c.Set(mov->GetColor().r, mov->GetColor().g, mov->GetColor().b, c.a); |
|
fMovies[i]->SetColor(c); |
|
} |
|
if( mov->GetCmd() & plMovieMsg::kOpacity ) |
|
{ |
|
hsColorRGBA c = fMovies[i]->GetColor(); |
|
c.a = mov->GetColor().a; |
|
fMovies[i]->SetColor(c); |
|
} |
|
if( mov->GetCmd() & plMovieMsg::kFadeIn ) |
|
{ |
|
fMovies[i]->SetFadeFromColor(mov->GetFadeInColor()); |
|
fMovies[i]->SetFadeFromTime(mov->GetFadeInSecs()); |
|
} |
|
if( mov->GetCmd() & plMovieMsg::kFadeOut ) |
|
{ |
|
fMovies[i]->SetFadeToColor(mov->GetFadeOutColor()); |
|
fMovies[i]->SetFadeToTime(mov->GetFadeOutSecs()); |
|
} |
|
if( mov->GetCmd() & plMovieMsg::kVolume ) |
|
fMovies[i]->SetVolume(mov->GetVolume()); |
|
|
|
if( mov->GetCmd() & plMovieMsg::kStart ) |
|
fMovies[i]->Start(fPipeline, fWindowHndl); |
|
if( mov->GetCmd() & plMovieMsg::kPause ) |
|
fMovies[i]->Pause(true); |
|
if( mov->GetCmd() & plMovieMsg::kResume ) |
|
fMovies[i]->Pause(false); |
|
if( mov->GetCmd() & plMovieMsg::kStop ) |
|
fMovies[i]->Stop(); |
|
|
|
// If a movie has lost its filename, it means something went horribly wrong |
|
// with playing it and it has shutdown. Or we just stopped it. Either way, |
|
// we need to clear it out of our list. |
|
if( !(fMovies[i]->GetFileName() && *fMovies[i]->GetFileName()) ) |
|
{ |
|
delete fMovies[i]; |
|
fMovies.Remove(i); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
int plClient::IFindRoomByLoc(const plLocation& loc) |
|
{ |
|
for (int i = 0; i < fRooms.Count(); i++) |
|
{ |
|
if (fRooms[i].fNode->GetKey()->GetUoid().GetLocation() == loc) |
|
return i; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
bool plClient::IIsRoomLoading(const plLocation& loc) |
|
{ |
|
for (int i = 0; i < fRoomsLoading.size(); i++) |
|
{ |
|
if (fRoomsLoading[i] == loc) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void plClient::SetHoldLoadRequests(bool hold) |
|
{ |
|
fHoldLoadRequests = hold; |
|
if (!fHoldLoadRequests) |
|
ILoadNextRoom(); |
|
} |
|
|
|
#include "../plResMgr/plPageInfo.h" |
|
|
|
void plClient::IQueueRoomLoad(const std::vector<plLocation>& locs, bool hold) |
|
{ |
|
bool allSameAge = true; |
|
const char* lastAgeName = nil; |
|
|
|
UInt32 numRooms = 0; |
|
for (int i = 0; i < locs.size(); i++) |
|
{ |
|
const plLocation& loc = locs[i]; |
|
|
|
const plPageInfo* info = plKeyFinder::Instance().GetLocationInfo(loc); |
|
bool alreadyLoaded = (IFindRoomByLoc(loc) != -1); |
|
bool isLoading = IIsRoomLoading(loc); |
|
if (!info || alreadyLoaded || isLoading) |
|
{ |
|
#ifdef HS_DEBUGGING |
|
if (!info) |
|
hsStatusMessageF("Ignoring LoadRoom request for location 0x%x because we can't find the location", loc.GetSequenceNumber()); |
|
else if (alreadyLoaded) |
|
hsStatusMessageF("Ignoring LoadRoom request for %s-%s, since room is already loaded", info->GetAge(), info->GetPage()); |
|
else if (isLoading) |
|
hsStatusMessageF("Ignoring LoadRoom request for %s-%s, since room is currently loading", info->GetAge(), info->GetPage()); |
|
#endif |
|
|
|
continue; |
|
} |
|
|
|
fLoadRooms.push_back(TRACKED_NEW LoadRequest(loc, hold)); |
|
|
|
if (!lastAgeName || hsStrEQ(info->GetAge(), lastAgeName)) |
|
lastAgeName = info->GetAge(); |
|
else |
|
allSameAge = false; |
|
|
|
// hsStatusMessageF("+++ Loading room %s-%s", info.GetAge(), info.GetPage()); |
|
numRooms++; |
|
} |
|
|
|
if (numRooms == 0) |
|
return; |
|
|
|
fNumLoadingRooms += numRooms; |
|
} |
|
|
|
void plClient::ILoadNextRoom() |
|
{ |
|
LoadRequest* req = nil; |
|
|
|
while (!fLoadRooms.empty()) |
|
{ |
|
req = fLoadRooms.front(); |
|
fLoadRooms.pop_front(); |
|
|
|
bool alreadyLoaded = (IFindRoomByLoc(req->loc) != -1); |
|
hsBool isLoading = IIsRoomLoading(req->loc); |
|
if (alreadyLoaded || isLoading) |
|
{ |
|
delete req; |
|
req = nil; |
|
fNumLoadingRooms--; |
|
} |
|
else |
|
break; |
|
} |
|
|
|
if (req) |
|
{ |
|
plClientRefMsg* pRefMsg = TRACKED_NEW plClientRefMsg(GetKey(), |
|
plRefMsg::kOnCreate, -1, |
|
req->hold ? plClientRefMsg::kLoadRoomHold : plClientRefMsg::kLoadRoom); |
|
|
|
fRoomsLoading.push_back(req->loc); // flag the location as currently loading |
|
|
|
// PageInPage is not guaranteed to finish synchronously, just FYI |
|
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr(); |
|
mgr->PageInRoom(req->loc, plSceneNode::Index(), pRefMsg); |
|
|
|
delete req; |
|
|
|
plClientMsg* nextRoom = TRACKED_NEW plClientMsg(plClientMsg::kLoadNextRoom); |
|
nextRoom->Send(GetKey()); |
|
} |
|
} |
|
|
|
void plClient::IUnloadRooms(const std::vector<plLocation>& locs) |
|
{ |
|
for (int i = 0; i < locs.size(); i++) |
|
{ |
|
const plLocation& loc = locs[i]; |
|
|
|
if (!loc.IsValid()) |
|
continue; |
|
|
|
plKey nodeKey = nil; |
|
|
|
// First, look in our room list. It *should* be there, which allows us to avoid a |
|
// potential nasty reload-find in the resMgr. |
|
int roomIdx = IFindRoomByLoc(loc); |
|
if (roomIdx != -1) |
|
nodeKey = fRooms[roomIdx].fNode->GetKey(); |
|
|
|
if (nodeKey == nil) |
|
{ |
|
nodeKey = plKeyFinder::Instance().FindSceneNodeKey(loc); |
|
} |
|
|
|
if (nodeKey != nil) |
|
{ |
|
plSceneNode* node = plSceneNode::ConvertNoRef(nodeKey->ObjectIsLoaded()); |
|
if (node) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plStatusLog::AddLineS("pageouts.log", "SceneNode for %s loaded; Removing node", node->GetKey()->GetUoid().GetObjectName()); |
|
#endif |
|
fPageMgr->RemoveNode(node); |
|
} |
|
else |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plStatusLog::AddLineS("pageouts.log", "SceneNode for %s NOT loaded", nodeKey->GetUoid().GetObjectName()); |
|
#endif |
|
} |
|
GetKey()->Release(nodeKey); // release notify interest in scene node |
|
|
|
UInt32 recFlags = 0; |
|
if (roomIdx != -1) |
|
{ |
|
recFlags = fRooms[roomIdx].fFlags; |
|
fRooms.Remove(roomIdx); |
|
} |
|
|
|
if (node == fCurrentNode) |
|
fCurrentNode = nil; |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plStatusLog::AddLineS("pageouts.log", "Telling netClientMgr about paging out %s", nodeKey->GetUoid().GetObjectName()); |
|
#endif |
|
|
|
if (plNetClientMgr::GetInstance() != nil) |
|
{ |
|
// Don't care really about the message that just came in, we care whether it was really held or not |
|
if (!hsCheckBits(recFlags, plRoomRec::kHeld)) |
|
plAgeLoader::GetInstance()->StartPagingOutRoom(&nodeKey, 1); |
|
// Tell NetClientManager not to expect any pageout info on this guy, since he was held |
|
else |
|
plAgeLoader::GetInstance()->IgnorePagingOutRoom(&nodeKey, 1); |
|
} |
|
} |
|
else |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// plStatusLog::AddLineS("pageouts.log", "++ Can't find node key for paging out room %s, loc 0x%x", |
|
// pMsg->GetRoomName() != nil ? pMsg->GetRoomName() : "", |
|
// loc.GetSequenceNumber()); |
|
#endif |
|
} |
|
} |
|
} |
|
|
|
void plClient::IRoomLoaded(plSceneNode* node, bool hold) |
|
{ |
|
fCurrentNode = node; |
|
// make sure we don't already have this room in the list: |
|
hsBool bAppend = true; |
|
for (int i = 0; i < fRooms.Count(); i++) |
|
{ |
|
if (fRooms[i].fNode == fCurrentNode) |
|
{ |
|
bAppend = false; |
|
break; |
|
} |
|
} |
|
if (bAppend) |
|
{ |
|
if (hold) |
|
{ |
|
fRooms.Append(plRoomRec(fCurrentNode, plRoomRec::kHeld)); |
|
} |
|
else |
|
{ |
|
fRooms.Append(plRoomRec(fCurrentNode, 0)); |
|
fPageMgr->AddNode(fCurrentNode); |
|
} |
|
} |
|
|
|
fNumLoadingRooms--; |
|
|
|
// Shut down the progress bar if that was the last room |
|
if (fProgressBar != nil && fNumLoadingRooms <= 0) |
|
{ |
|
#ifdef MSG_LOADING_BAR |
|
if (!hold) |
|
{ |
|
struct AgeMsgCount { const char* AgeName; int NumMsgs; }; |
|
static AgeMsgCount ageMsgCount[] = |
|
{ |
|
{ "BahroCave", 2600 }, |
|
{ "BaronCityOffice", 670 }, |
|
{ "city", 269000 }, |
|
{ "Cleft", 11000 }, |
|
{ "Garden", 19700 }, |
|
{ "Garrison", 28800 }, |
|
{ "Gira", 3300 }, |
|
{ "Kadish", 19700 }, |
|
{ "Neighborhood", 19900 }, |
|
{ "Nexus", 1400 }, |
|
{ "Personal", 20300 }, |
|
{ "Teledahn", 48000 } |
|
}; |
|
|
|
char name[256]; |
|
strcpy(name, &fProgressBar->GetTitle()[strlen("Loading ")]); |
|
name[strlen(name)-3] = '\0'; |
|
|
|
// Get the precalculated value for how many messages will be |
|
// sent out before the screen actually fades in |
|
int numMsgs = 0; |
|
for (int i = 0; i < sizeof(ageMsgCount)/sizeof(AgeMsgCount); i++) |
|
{ |
|
if (hsStrEQ(ageMsgCount[i].AgeName, name)) |
|
{ |
|
numMsgs = ageMsgCount[i].NumMsgs; |
|
break; |
|
} |
|
} |
|
|
|
fNumPostLoadMsgs = 0; |
|
|
|
// The last 10% of the age loading bar is for messages, so adjust |
|
// our progress bar increment to fill the bar fully when all |
|
// messages have been sent |
|
float max = fProgressBar->GetMax(); |
|
float amtLeft = max - (max * 0.9f); |
|
fPostLoadMsgInc = (numMsgs != 0) ? amtLeft / numMsgs : 0; |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
if (plDispatchLogBase::IsLogging()) |
|
plDispatchLogBase::GetInstance()->LogStatusBarChange(fProgressBar->GetTitle(), "displaying messages"); |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
#endif |
|
} |
|
} |
|
|
|
hsRefCnt_SafeUnRef(fCurrentNode); |
|
plKey pRmKey = fCurrentNode->GetKey(); |
|
plAgeLoader::GetInstance()->FinishedPagingInRoom(&pRmKey, 1); |
|
// *** this used to call "ActivateNode" (in physics) which wasn't implemented. |
|
// *** we should make this "turn on" physics for the selected node |
|
// *** depending on what guarantees we can make about the load state -- anything useful? |
|
|
|
// now tell all those who are interested that a room was loaded |
|
if (!hold) |
|
{ |
|
plRoomLoadNotifyMsg* loadmsg = TRACKED_NEW plRoomLoadNotifyMsg; |
|
loadmsg->SetRoom(pRmKey); |
|
loadmsg->SetWhatHappen(plRoomLoadNotifyMsg::kLoaded); |
|
plgDispatch::MsgSend(loadmsg); |
|
} |
|
else |
|
hsStatusMessageF("Done loading hold room %s, t=%f\n", pRmKey->GetName(), hsTimer::GetSeconds()); |
|
|
|
plLocation loc = pRmKey->GetUoid().GetLocation(); |
|
for (int i = 0; i < fRoomsLoading.size(); i++) |
|
{ |
|
if (fRoomsLoading[i] == loc) |
|
{ |
|
fRoomsLoading.erase(fRoomsLoading.begin() + i); |
|
break; |
|
} |
|
} |
|
|
|
if (!fNumLoadingRooms) |
|
IStopProgress(); |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IRoomUnloaded(plSceneNode* node) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plStatusLog::AddLineS("pageouts.log", ".. refMsg is onDestroy"); |
|
#endif |
|
|
|
fCurrentNode = node; |
|
hsRefCnt_SafeUnRef(fCurrentNode); |
|
plKey pRmKey = fCurrentNode->GetKey(); |
|
if (plAgeLoader::GetInstance()) |
|
plAgeLoader::GetInstance()->FinishedPagingOutRoom(&pRmKey, 1); |
|
|
|
// tell all those who are interested that a room was unloaded |
|
plRoomLoadNotifyMsg* loadmsg = TRACKED_NEW plRoomLoadNotifyMsg; |
|
loadmsg->SetRoom(pRmKey); |
|
loadmsg->SetWhatHappen(plRoomLoadNotifyMsg::kUnloaded); |
|
plgDispatch::MsgSend(loadmsg); |
|
} |
|
|
|
void plClient::IReadKeyedObjCallback(plKey key) |
|
{ |
|
fInstance->IIncProgress(1, key->GetName()); |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IProgressMgrCallbackProc(plOperationProgress * progress) |
|
{ |
|
if(!fInstance) |
|
return; |
|
|
|
fInstance->fMessagePumpProc(); |
|
fInstance->IDraw(); |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IIncProgress (hsScalar byHowMuch, const char * text) |
|
{ |
|
if (fProgressBar) { |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
fProgressBar->SetStatusText( text ); |
|
#endif |
|
fProgressBar->Increment( byHowMuch ); |
|
} |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IStartProgress( const char *title, hsScalar len ) |
|
{ |
|
if (fProgressBar) |
|
{ |
|
fProgressBar->SetLength(fProgressBar->GetMax()+len); |
|
} |
|
else |
|
{ |
|
fProgressBar = plProgressMgr::GetInstance()->RegisterOperation(len, title, plProgressMgr::kNone, false, true); |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
if (plDispatchLogBase::IsLogging()) |
|
plDispatchLogBase::GetInstance()->LogStatusBarChange(fProgressBar->GetTitle(), "starting"); |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
|
|
((plResManager*)hsgResMgr::ResMgr())->SetProgressBarProc(IReadKeyedObjCallback); |
|
plDispatch::SetMsgRecieveCallback(IDispatchMsgReceiveCallback); |
|
|
|
fLastProgressUpdate = 0.f; |
|
} |
|
// Workaround for NVidia driver bug, showing up as BCO not there first time. |
|
// See Mantis bug 0014590. |
|
if( fPipeline ) |
|
fPipeline->LoadResources(); |
|
} |
|
|
|
|
|
//============================================================================ |
|
void plClient::IStopProgress( void ) |
|
{ |
|
if (fProgressBar) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
if (plDispatchLogBase::IsLogging()) |
|
plDispatchLogBase::GetInstance()->LogStatusBarChange(fProgressBar->GetTitle(), "done"); |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
|
|
plDispatch::SetMsgRecieveCallback(nil); |
|
((plResManager*)hsgResMgr::ResMgr())->SetProgressBarProc(IReadKeyedObjCallback); |
|
delete fProgressBar; |
|
fProgressBar = nil; |
|
|
|
plPipeResReq::Request(); |
|
|
|
fFlags.SetBit(kFlagGlobalDataLoaded); |
|
if (fFlags.IsBitSet(kFlagAsyncInitComplete)) |
|
ICompleteInit(); |
|
} |
|
} |
|
|
|
/***************************************************************************** |
|
* |
|
* |
|
* |
|
***/ |
|
|
|
extern hsBool gDataServerLocal; |
|
|
|
#include "plQuality.h" |
|
#include "plLoadMask.h" |
|
|
|
#if 0 |
|
class LoginNetClientCommCallback : public plNetClientComm::Callback |
|
{ |
|
public: |
|
enum Op {kAuth, kCreatePlayer, kGetPlayerList, kLeave, kDeletePlayer}; |
|
|
|
LoginNetClientCommCallback() : plNetClientComm::Callback(), fNumCurrentOps(0) |
|
{} |
|
|
|
virtual void OperationStarted( UInt32 context ) |
|
{ |
|
fNumCurrentOps++; |
|
} |
|
virtual void OperationComplete( UInt32 context, int resultCode ) |
|
{ |
|
if (context == kAuth) |
|
{ |
|
if (hsSucceeded(resultCode)) |
|
{ |
|
plClient::GetInstance()->fAuthPassed = true; |
|
} |
|
} |
|
else if (context == kGetPlayerList) |
|
{ |
|
if ( hsSucceeded( resultCode ) ) |
|
{ |
|
UInt32 numPlayers = fCbArgs.GetInt(0); |
|
UInt32 pId = -1; |
|
std::string pName; |
|
|
|
for (UInt32 i = 0; i < numPlayers; i++) |
|
{ |
|
pId = fCbArgs.GetInt((UInt16)(i*3+1)); |
|
pName = fCbArgs.GetString((UInt16)(i*3+2)); |
|
|
|
if (pName == plClient::GetInstance()->fUsername) |
|
{ |
|
plClient::GetInstance()->fPlayerID = pId; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
else if (context == kCreatePlayer) |
|
{ |
|
if (hsSucceeded(resultCode)) |
|
plClient::GetInstance()->fPlayerID = fCbArgs.GetInt(0); |
|
} |
|
else if (context == kDeletePlayer) |
|
{ |
|
if (hsSucceeded(resultCode)) |
|
plClient::GetInstance()->fPlayerID = -1; |
|
} |
|
|
|
fNumCurrentOps--; |
|
} |
|
|
|
bool IsActive() |
|
{ |
|
return fNumCurrentOps > 0; |
|
} |
|
|
|
private: |
|
int fNumCurrentOps; |
|
}; |
|
#endif |
|
|
|
//============================================================================ |
|
hsBool plClient::StartInit() |
|
{ |
|
hsStatusMessage("Init client\n"); |
|
fFlags.SetBit( kFlagIniting ); |
|
|
|
pfLocalizationMgr::Initialize("dat"); |
|
|
|
plQuality::SetQuality(fQuality); |
|
if( (GetClampCap() >= 0) && (GetClampCap() < plQuality::GetCapability()) ) |
|
plQuality::SetCapability(GetClampCap()); |
|
|
|
/// 2.16.2001 mcn - Moved console engine init to constructor, |
|
/// so we could use console commands even before the pipeline init |
|
|
|
plDTProgressMgr::DeclareThyself(); |
|
|
|
// Set our callback for the progress manager so everybody else can use it |
|
fLastProgressUpdate = 0.f; |
|
plProgressMgr::GetInstance()->SetCallbackProc( IProgressMgrCallbackProc ); |
|
|
|
// Check the registry, which deletes data files that are either corrupt or |
|
// have old version numbers. If the file still exists on the file server |
|
// then it will be patched on-the-fly as needed (unless you're running with |
|
// local data of course). |
|
((plResManager *)hsgResMgr::ResMgr())->VerifyPages(); |
|
|
|
// the dx8 audio system MUST be initialized |
|
// before the database is loaded |
|
HWND hWnd = fWindowHndl; |
|
SetForegroundWindow(fWindowHndl); |
|
|
|
plgAudioSys::Init(hWnd); |
|
gAudio = plgAudioSys::Sys(); |
|
|
|
RegisterAs( kClient_KEY ); |
|
|
|
InitDLLs(); |
|
|
|
plGlobalVisMgr::Init(); |
|
fPageMgr = TRACKED_NEW plPageTreeMgr; |
|
|
|
plVisLOSMgr::Init(fPipeline, fPageMgr); |
|
|
|
// init globals |
|
plAvatarMgr::GetInstance(); |
|
plRelevanceMgr::Init(); |
|
|
|
gDisp = plgDispatch::Dispatch(); |
|
gTimerMgr = plgTimerCallbackMgr::Mgr(); |
|
|
|
// |
|
// initialize input system |
|
// |
|
InitInputs(); |
|
|
|
/// Init the console object |
|
/// Note: this can be done last because the console engine was inited first, and |
|
/// everything in code that works with the console does so through the console engine |
|
|
|
fConsole = TRACKED_NEW pfConsole(); |
|
pfConsole::SetPipeline( fPipeline ); |
|
fConsole->RegisterAs( kConsoleObject_KEY ); // fixedKey from plFixedKey.h |
|
fConsole->Init( fConsoleEngine ); |
|
|
|
/// Init the font cache |
|
fFontCache = TRACKED_NEW plFontCache(); |
|
|
|
/// Init the transition manager |
|
fTransitionMgr = TRACKED_NEW plTransitionMgr(); |
|
fTransitionMgr->RegisterAs( kTransitionMgr_KEY ); // fixedKey from plFixedKey.h |
|
fTransitionMgr->Init(); |
|
|
|
// Init the Age Linking effects manager |
|
fLinkEffectsMgr = TRACKED_NEW plLinkEffectsMgr(); |
|
fLinkEffectsMgr->RegisterAs( kLinkEffectsMgr_KEY ); // fixedKey from plFixedKey.h |
|
fLinkEffectsMgr->Init(); |
|
|
|
/// Init the in-game GUI manager |
|
fGameGUIMgr = TRACKED_NEW pfGameGUIMgr(); |
|
fGameGUIMgr->RegisterAs( kGameGUIMgr_KEY ); |
|
fGameGUIMgr->Init(); |
|
|
|
plgAudioSys::Activate(true); |
|
|
|
plConst(hsScalar) delay(2.f); |
|
//commenting out publisher splash for MORE |
|
//IPlayIntroBink("avi/intro0.bik", delay, 0.f, 0.f, 1.f, 1.f, 0.75); |
|
//if( GetDone() ) return false; |
|
IPlayIntroBink("avi/intro1.bik", 0.f, 0.f, 0.f, 1.f, 1.f, 0.75); |
|
if( GetDone() ) return false; |
|
plgDispatch::Dispatch()->RegisterForExactType(plMovieMsg::Index(), GetKey()); |
|
|
|
// |
|
// Init Net before loading things |
|
// |
|
plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); |
|
plNetClientMgr::GetInstance()->Init(); |
|
plAgeLoader::GetInstance()->Init(); |
|
pfSecurePreloader::GetInstance()->Init(); |
|
|
|
plCmdIfaceModMsg* pModMsg2 = TRACKED_NEW plCmdIfaceModMsg; |
|
pModMsg2->SetBCastFlag(plMessage::kBCastByExactType); |
|
pModMsg2->SetSender(fConsole->GetKey()); |
|
pModMsg2->SetCmd(plCmdIfaceModMsg::kAdd); |
|
plgDispatch::MsgSend(pModMsg2); |
|
|
|
// create new the virtual camera |
|
fNewCamera = TRACKED_NEW plVirtualCam1; |
|
fNewCamera->RegisterAs( kVirtualCamera1_KEY ); |
|
fNewCamera->Init(); |
|
fNewCamera->SetPipeline( GetPipeline() ); |
|
|
|
float aspectratio = (float)fPipeline->Width() / (float)fPipeline->Height(); |
|
plVirtualCam1::SetAspectRatio(aspectratio); |
|
plVirtualCam1::SetFOV(plVirtualCam1::GetFOVw(), plVirtualCam1::GetFOVh()); |
|
|
|
pfGameGUIMgr::GetInstance()->SetAspectRatio( aspectratio ); |
|
plMouseDevice::Instance()->SetDisplayResolution((float)fPipeline->Width(), (float)fPipeline->Height()); |
|
|
|
// create the listener for the audio system: |
|
plListener* pLMod = TRACKED_NEW plListener; |
|
pLMod->RegisterAs(kListenerMod_KEY ); |
|
|
|
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), pLMod->GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey()); |
|
|
|
plSynchedObject::PushSynchDisabled(false); // enable dirty tracking |
|
|
|
if (StrCmp(NetCommGetStartupAge()->ageDatasetName, "StartUp") == 0) |
|
{ |
|
plNetCommAuthMsg * msg = NEW(plNetCommAuthMsg); |
|
msg->result = kNetSuccess; |
|
msg->param = nil; |
|
msg->Send(); |
|
} |
|
|
|
// 2nd half of plClient initialization occurs after |
|
// all network events have completed. Async events: |
|
// |
|
// 1) Download secure files |
|
// |
|
// Continue plClient init via IOnAsyncInitComplete(). |
|
|
|
return true; |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IPatchGlobalAgeFiles( void ) |
|
{ |
|
const char * ageFiles[] = { |
|
"GlobalAnimations", |
|
"GlobalAvatars", |
|
"GlobalClothing", |
|
"GlobalMarkers", |
|
"GUI", |
|
"CustomAvatars" |
|
}; |
|
|
|
for (unsigned i = 0; i < arrsize(ageFiles); ++i) { |
|
plResPatcher myPatcher(ageFiles[i], true); |
|
|
|
if (gDataServerLocal) |
|
break; |
|
|
|
if (!myPatcher.Update()) { |
|
SetDone(true); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
void plClient::InitDLLs() |
|
{ |
|
hsStatusMessage("Init dlls client\n"); |
|
char str[255]; |
|
typedef void (*PInitGlobalsFunc) (hsResMgr *, plFactory *, plTimerCallbackManager *, plTimerShare*, |
|
plNetClientApp*); |
|
|
|
hsFolderIterator modDllFolder("ModDLL\\"); |
|
while (modDllFolder.NextFileSuffix(".dll")) |
|
{ |
|
modDllFolder.GetPathAndName(str); |
|
HMODULE hMod = LoadLibrary(str); |
|
if (hMod) |
|
{ |
|
PInitGlobalsFunc initGlobals = (PInitGlobalsFunc)GetProcAddress(hMod, "InitGlobals"); |
|
initGlobals(hsgResMgr::ResMgr(), plFactory::GetTheFactory(), plgTimerCallbackMgr::Mgr(), |
|
hsTimer::GetTheTimer(), plNetClientApp::GetInstance()); |
|
fLoadedDLLs.Append(hMod); |
|
} |
|
} |
|
} |
|
|
|
void plClient::ShutdownDLLs() |
|
{ |
|
int j; |
|
for( j = 0; j < fLoadedDLLs.GetCount(); j++ ) |
|
{ |
|
BOOL ret = FreeLibrary(fLoadedDLLs[j]); |
|
if( !ret ) |
|
hsStatusMessage("Failed to free lib\n"); |
|
} |
|
fLoadedDLLs.Reset(); |
|
} |
|
|
|
hsBool plClient::MainLoop() |
|
{ |
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
if (PythonInterface::UsePythonDebugger()) |
|
{ |
|
PythonInterface::PythonDebugger()->Update(); |
|
|
|
if (PythonInterface::PythonDebugger()->IsConnected()) |
|
{ |
|
bPythonDebugConnected = true; |
|
if (PythonInterface::DebuggerRequestedExit() && PythonInterface::PythonDebugger()->ExitOnStop()) |
|
SetDone(true); // debugger requested that we stop running, so exit nicely |
|
} |
|
else |
|
bPythonDebugConnected = false; |
|
} |
|
#endif |
|
|
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
if (DebugIsDebuggerPresent()) |
|
{ |
|
NetCliAuthLogClientDebuggerConnect(); |
|
SetDone(true); |
|
} |
|
#endif |
|
|
|
if(plClient::fDelayMS) |
|
Sleep(5); |
|
|
|
// Reset our stats |
|
plProfileManager::Instance().BeginFrame(); |
|
|
|
if (IUpdate()) |
|
return true; |
|
|
|
if (IDraw()) |
|
return true; |
|
|
|
plProfileManagerFull::Instance().EndFrame(); |
|
plProfileManager::Instance().EndFrame(); |
|
|
|
// Draw the stats |
|
plProfileManagerFull::Instance().Update(); |
|
|
|
return false; |
|
} |
|
|
|
#include "plProfile.h" |
|
|
|
plProfile_Extern(DrawTime); |
|
plProfile_Extern(UpdateTime); |
|
plProfile_CreateTimer("ResMgr", "Update", ResMgr); |
|
plProfile_CreateTimer("DispatchQueue", "Update", DispatchQueue); |
|
plProfile_CreateTimer("RenderSetup", "Update", RenderMsg); |
|
plProfile_CreateTimer("Simulation", "Update", Simulation); |
|
plProfile_CreateTimer("NetTime", "Update", UpdateNetTime); |
|
plProfile_Extern(TimeMsg); |
|
plProfile_Extern(EvalMsg); |
|
plProfile_Extern(TransformMsg); |
|
plProfile_Extern(CameraMsg); |
|
plProfile_Extern(AnimatingPhysicals); |
|
plProfile_Extern(StoppedAnimPhysicals); |
|
|
|
plProfile_CreateTimer("BeginRender", "Render", BeginRender); |
|
plProfile_CreateTimer("ClearRender", "Render", ClearRender); |
|
plProfile_CreateTimer("PreRender", "Render", PreRender); |
|
plProfile_CreateTimer("MainRender", "Render", MainRender); |
|
plProfile_CreateTimer("PostRender", "Render", PostRender); |
|
plProfile_CreateTimer("Movies", "Render", Movies); |
|
plProfile_CreateTimer("Console", "Render", Console); |
|
plProfile_CreateTimer("StatusLog", "Render", StatusLog); |
|
plProfile_CreateTimer("ProgressMgr", "Render", ProgressMgr); |
|
plProfile_CreateTimer("ScreenElem", "Render", ScreenElem); |
|
plProfile_CreateTimer("EndRender", "Render", EndRender); |
|
|
|
|
|
hsBool plClient::IUpdate() |
|
{ |
|
plProfile_BeginTiming(UpdateTime); |
|
|
|
// reset timer on first frame if realtime and not clamping, to avoid initial large delta |
|
if (hsTimer::GetSysSeconds()==0 && hsTimer::IsRealTime() && hsTimer::GetTimeClamp()==0) |
|
hsTimer::SetRealTime(true); |
|
|
|
plProfile_BeginTiming(DispatchQueue); |
|
plgDispatch::Dispatch()->MsgQueueProcess(); |
|
plProfile_EndTiming(DispatchQueue); |
|
|
|
const char *inputUpdate = "Update"; |
|
if (fInputManager) // Is this used anymore? Seems to always be nil. |
|
fInputManager->Update(); |
|
|
|
hsTimer::IncSysSeconds(); |
|
plClientUnifiedTime::SetSysTime(); // keep a unified time, based on sysSeconds |
|
// Time may have been clamped in IncSysSeconds, depending on hsTimer's current mode. |
|
|
|
double currTime = hsTimer::GetSysSeconds(); |
|
hsScalar delSecs = hsTimer::GetDelSysSeconds(); |
|
|
|
// do not change this ordering |
|
|
|
plProfile_BeginTiming(UpdateNetTime); |
|
plNetClientMgr::GetInstance()->Update(currTime); |
|
plProfile_EndTiming(UpdateNetTime); |
|
|
|
// update python |
|
//plCaptureRender::Update(fPipeline); |
|
plCaptureRender::Update(); |
|
cyMisc::Update(currTime); |
|
|
|
// This TimeMsg doesn't really do much, except somehow it flushes the dispatch |
|
// after the NetClientMgr updates, delivering any SelfDestruct messages in the |
|
// queue. This is important to prevent objects that are about to go away from |
|
// starting trouble during their update. So to get rid of this message, some |
|
// other way of flushing the dispatch after NegClientMgr's update is needed. mf |
|
plProfile_BeginTiming(TimeMsg); |
|
plTimeMsg* msg = TRACKED_NEW plTimeMsg(nil, nil, nil, nil); |
|
plgDispatch::MsgSend(msg); |
|
plProfile_EndTiming(TimeMsg); |
|
|
|
plProfile_BeginTiming(EvalMsg); |
|
plEvalMsg* eval = TRACKED_NEW plEvalMsg(nil, nil, nil, nil); |
|
plgDispatch::MsgSend(eval); |
|
plProfile_EndTiming(EvalMsg); |
|
|
|
char *xFormLap1 = "Main"; |
|
plProfile_BeginLap(TransformMsg, xFormLap1); |
|
plTransformMsg* xform = TRACKED_NEW plTransformMsg(nil, nil, nil, nil); |
|
plgDispatch::MsgSend(xform); |
|
plProfile_EndLap(TransformMsg, xFormLap1); |
|
|
|
plCoordinateInterface::SetTransformPhase(plCoordinateInterface::kTransformPhaseDelayed); |
|
|
|
if (fAnimDebugList) |
|
fAnimDebugList->ShowReport(); |
|
|
|
plProfile_BeginTiming(Simulation); |
|
plSimulationMgr::GetInstance()->Advance(delSecs); |
|
plProfile_EndTiming(Simulation); |
|
|
|
// At this point, we just register for a plDelayedTransformMsg when dirtied. |
|
if (!plCoordinateInterface::GetDelayedTransformsEnabled()) |
|
{ |
|
char *xFormLap2 = "Simulation"; |
|
plProfile_BeginLap(TransformMsg, xFormLap2); |
|
xform = TRACKED_NEW plTransformMsg(nil, nil, nil, nil); |
|
plgDispatch::MsgSend(xform); |
|
plProfile_EndLap(TransformMsg, xFormLap2); |
|
} |
|
else |
|
{ |
|
char *xFormLap3 = "Delayed"; |
|
plProfile_BeginLap(TransformMsg, xFormLap3); |
|
xform = TRACKED_NEW plDelayedTransformMsg(nil, nil, nil, nil); |
|
plgDispatch::MsgSend(xform); |
|
plProfile_EndLap(TransformMsg, xFormLap3); |
|
} |
|
|
|
plCoordinateInterface::SetTransformPhase(plCoordinateInterface::kTransformPhaseNormal); |
|
|
|
plProfile_BeginTiming(CameraMsg); |
|
plCameraMsg* cameras = TRACKED_NEW plCameraMsg; |
|
cameras->SetCmd(plCameraMsg::kUpdateCameras); |
|
cameras->SetBCastFlag(plMessage::kBCastByExactType); |
|
plgDispatch::MsgSend(cameras); |
|
plProfile_EndTiming(CameraMsg); |
|
|
|
if (fPatchGlobalAges) |
|
{ |
|
// Download or patch our global ages, if necessary |
|
IPatchGlobalAgeFiles(); |
|
IOnAsyncInitComplete(); |
|
|
|
fPatchGlobalAges = false; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
hsBool plClient::IDrawProgress() { |
|
// HACK: Don't draw while we're caching some room loads, otherwise the |
|
// progress bar will jump around while we're calculating the size |
|
if (fHoldLoadRequests) |
|
return false; |
|
|
|
// Reset our stats |
|
plProfileManager::Instance().BeginFrame(); |
|
|
|
plProfile_BeginTiming(DrawTime); |
|
if( fPipeline->BeginRender() ) |
|
{ |
|
return IFlushRenderRequests(); |
|
} |
|
// Override the clear color to black. |
|
fPipeline->ClearRenderTarget(&hsColorRGBA().Set(0.f, 0.f, 0.f, 1.f)); |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
fConsole->Draw( fPipeline ); |
|
#endif |
|
|
|
plStatusLogMgr::GetInstance().Draw(); |
|
plProgressMgr::GetInstance()->Draw( fPipeline ); |
|
fPipeline->RenderScreenElements(); |
|
fPipeline->EndRender(); |
|
plProfile_EndTiming(DrawTime); |
|
|
|
plProfileManager::Instance().EndFrame(); |
|
|
|
return false; |
|
} |
|
|
|
hsBool plClient::IDraw() |
|
{ |
|
// Limit framerate |
|
static float lastDrawTime; |
|
static const float kMaxFrameRate = 1.f/30.f; |
|
float currTime = (float) hsTimer::GetSeconds(); |
|
if (!fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNVPerfHUD)) |
|
{ |
|
// If we're using NVPerfHUD to step through draw calls, |
|
// We're going to have a frame delta of zero. In that |
|
// case we need to draw no matter what, and we don't |
|
// care as much about starving other threads because |
|
// we're presumably just debugging a graphics glitch. |
|
if ((currTime - lastDrawTime) < kMaxFrameRate) |
|
return true; |
|
} |
|
lastDrawTime = currTime; |
|
|
|
// If we're shutting down, don't attempt to draw. Doing so |
|
// tends to cause a device reload each frame. |
|
if (fDone) |
|
return true; |
|
|
|
if (plProgressMgr::GetInstance()->IsActive()) |
|
return IDrawProgress(); |
|
|
|
plProfile_Extern(VisEval); |
|
plProfile_BeginTiming(VisEval); |
|
plGlobalVisMgr::Instance()->Eval(fPipeline->GetViewPositionWorld()); |
|
plProfile_EndTiming(VisEval); |
|
|
|
plProfile_BeginTiming(RenderMsg); |
|
plRenderMsg* rendMsg = TRACKED_NEW plRenderMsg(fPipeline); |
|
plgDispatch::MsgSend(rendMsg); |
|
plProfile_EndTiming(RenderMsg); |
|
|
|
plPreResourceMsg* preMsg = TRACKED_NEW plPreResourceMsg(fPipeline); |
|
plgDispatch::MsgSend(preMsg); |
|
|
|
// This might not be the ideal place for this, but it |
|
// needs to be AFTER the plRenderMsg is sent, and |
|
// BEFORE BeginRender. (plRenderMsg causes construction of |
|
// Dynamic objects (e.g. RT's), BeginRender uses them (e.g. shadows). |
|
if( plPipeResReq::Check() || fPipeline->CheckResources() ) |
|
{ |
|
fPipeline->LoadResources(); |
|
} |
|
|
|
plProfile_EndTiming(UpdateTime); |
|
|
|
plProfile_BeginTiming(DrawTime); |
|
|
|
plProfile_BeginTiming(BeginRender); |
|
if( fPipeline->BeginRender() ) |
|
{ |
|
plProfile_EndTiming(BeginRender); |
|
return IFlushRenderRequests(); |
|
} |
|
plProfile_EndTiming(BeginRender); |
|
|
|
plProfile_BeginTiming(ClearRender); |
|
fPipeline->ClearRenderTarget(); |
|
plProfile_EndTiming(ClearRender); |
|
|
|
plProfile_BeginTiming(PreRender); |
|
if( !fFlags.IsBitSet( kFlagDBGDisableRRequests ) ) |
|
IProcessPreRenderRequests(); |
|
plProfile_EndTiming(PreRender); |
|
|
|
plProfile_BeginTiming(MainRender); |
|
if( !fFlags.IsBitSet( kFlagDBGDisableRender ) ) |
|
fPageMgr->Render(fPipeline); |
|
plProfile_EndTiming(MainRender); |
|
|
|
plProfile_BeginTiming(PostRender); |
|
if( !fFlags.IsBitSet( kFlagDBGDisableRRequests ) ) |
|
IProcessPostRenderRequests(); |
|
plProfile_EndTiming(PostRender); |
|
|
|
plProfile_BeginTiming(Movies); |
|
IServiceMovies(); |
|
plProfile_EndTiming(Movies); |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
plProfile_BeginTiming(Console); |
|
fConsole->Draw( fPipeline ); |
|
plProfile_EndTiming(Console); |
|
#endif |
|
|
|
plProfile_BeginTiming(StatusLog); |
|
plStatusLogMgr::GetInstance().Draw(); |
|
plProfile_EndTiming(StatusLog); |
|
|
|
plProfile_BeginTiming(ProgressMgr); |
|
plProgressMgr::GetInstance()->Draw( fPipeline ); |
|
plProfile_EndTiming(ProgressMgr); |
|
|
|
fLastProgressUpdate = hsTimer::GetSeconds(); |
|
|
|
plProfile_BeginTiming(ScreenElem); |
|
fPipeline->RenderScreenElements(); |
|
plProfile_EndTiming(ScreenElem); |
|
|
|
plProfile_BeginTiming(EndRender); |
|
fPipeline->EndRender(); |
|
plProfile_EndTiming(EndRender); |
|
|
|
plProfile_EndTiming(DrawTime); |
|
|
|
return false; |
|
} |
|
|
|
void plClient::IServiceMovies() |
|
{ |
|
int i; |
|
for( i = 0; i < fMovies.GetCount(); i++ ) |
|
{ |
|
hsAssert(fMovies[i]->GetFileName() && *fMovies[i]->GetFileName(), "Lost our movie"); |
|
if( !fMovies[i]->NextFrame() ) |
|
{ |
|
delete fMovies[i]; |
|
fMovies.Remove(i); |
|
i--; |
|
} |
|
} |
|
} |
|
|
|
void plClient::IKillMovies() |
|
{ |
|
int i; |
|
for( i = 0; i < fMovies.GetCount(); i++ ) |
|
delete fMovies[i]; |
|
fMovies.Reset(); |
|
} |
|
|
|
hsBool plClient::IPlayIntroBink(const char* movieName, hsScalar endDelay, hsScalar posX, hsScalar posY, hsScalar scaleX, hsScalar scaleY, hsScalar volume /* = 1.0 */) |
|
{ |
|
SetQuitIntro(false); |
|
plBinkPlayer player; |
|
player.SetPosition(posX, posY); |
|
player.SetScale(scaleX, scaleY); |
|
player.SetFileName(movieName); |
|
player.SetFadeToTime(endDelay); |
|
player.SetFadeToColor(hsColorRGBA().Set(0, 0, 0, 1.f)); |
|
player.SetVolume(volume); |
|
bool firstTry = true; // flag to make sure that we don't quit before we even start |
|
|
|
if( player.Start(fPipeline, fWindowHndl) ) |
|
{ |
|
while( true ) |
|
{ |
|
if( fInstance ) |
|
fInstance->fMessagePumpProc(); |
|
|
|
if( GetDone() ) |
|
return true; |
|
if (firstTry) |
|
{ |
|
firstTry = false; |
|
SetQuitIntro(false); |
|
} |
|
else |
|
{ |
|
if( GetQuitIntro() ) |
|
return true; |
|
} |
|
|
|
hsBool done = false; |
|
if( !fPipeline->BeginRender() ) |
|
{ |
|
fPipeline->ClearRenderTarget(); |
|
done = !player.NextFrame(); |
|
|
|
fPipeline->EndRender(); |
|
} |
|
|
|
if( done ) |
|
return true; |
|
} |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
hsBool plClient::IFlushRenderRequests() |
|
{ |
|
// For those requesting ack's, we could go through and send them |
|
// mail telling them their request was ill-timed. But hopefully, |
|
// the lack of an acknowledgement will serve as notice. |
|
int i; |
|
for( i = 0; i < fPreRenderRequests.GetCount(); i++ ) |
|
hsRefCnt_SafeUnRef(fPreRenderRequests[i]); |
|
fPreRenderRequests.Reset(); |
|
|
|
for( i = 0; i < fPostRenderRequests.GetCount(); i++ ) |
|
hsRefCnt_SafeUnRef(fPostRenderRequests[i]); |
|
fPostRenderRequests.Reset(); |
|
|
|
return false; |
|
} |
|
|
|
void plClient::IProcessRenderRequests(hsTArray<plRenderRequest*>& reqs) |
|
{ |
|
int i; |
|
for( i = 0; i < reqs.GetCount(); i++ ) |
|
{ |
|
reqs[i]->Render(fPipeline, fPageMgr); |
|
hsRefCnt_SafeUnRef(reqs[i]); |
|
} |
|
reqs.SetCount(0); |
|
} |
|
|
|
void plClient::IProcessPreRenderRequests() |
|
{ |
|
IProcessRenderRequests(fPreRenderRequests); |
|
} |
|
|
|
void plClient::IProcessPostRenderRequests() |
|
{ |
|
IProcessRenderRequests(fPostRenderRequests); |
|
} |
|
|
|
void plClient::IAddRenderRequest(plRenderRequest* req) |
|
{ |
|
if( req->GetPriority() < 0 ) |
|
{ |
|
int i; |
|
for( i = 0; i < fPreRenderRequests.GetCount(); i++ ) |
|
{ |
|
if( req->GetPriority() < fPreRenderRequests[i]->GetPriority() ) |
|
break; |
|
} |
|
fPreRenderRequests.Insert(i, req); |
|
hsRefCnt_SafeRef(req); |
|
} |
|
else |
|
{ |
|
int i; |
|
for( i = 0; i < fPostRenderRequests.GetCount(); i++ ) |
|
{ |
|
if( req->GetPriority() < fPostRenderRequests[i]->GetPriority() ) |
|
break; |
|
} |
|
fPostRenderRequests.Insert(i, req); |
|
hsRefCnt_SafeRef(req); |
|
} |
|
} |
|
|
|
hsG3DDeviceModeRecord plClient::ILoadDevMode(const char* devModeFile) |
|
{ |
|
hsStatusMessage("Load DevMode client\n"); |
|
HWND hWnd = fWindowHndl; |
|
|
|
hsUNIXStream stream; |
|
hsBool gottaCreate = false; |
|
|
|
// If DevModeFind is specified, use the old method |
|
// if ((GetGameFlags() & kDevModeFind)) |
|
// FindAndSaveDevMode(hWnd, devModeFile); |
|
// Otherwise, use the new method |
|
hsG3DDeviceModeRecord dmr; |
|
if (stream.Open(devModeFile, "rb")) |
|
{ |
|
/// It's there, but is the device record valid? |
|
hsG3DDeviceRecord selRec; |
|
hsG3DDeviceMode selMode; |
|
|
|
selRec.Read(&stream); |
|
if( selRec.IsInvalid() ) |
|
{ |
|
hsStatusMessage( "WARNING: Old DeviceRecord found on file. Setting defaults..." ); |
|
gottaCreate = true; |
|
} |
|
else |
|
{ |
|
/// Read the rest in |
|
selMode.Read(&stream); |
|
|
|
UInt16 performance = stream.ReadSwap16(); |
|
|
|
if( performance < 25 ) |
|
plBitmap::SetGlobalLevelChopCount( 2 ); |
|
else if( performance < 75 ) |
|
plBitmap::SetGlobalLevelChopCount( 1 ); |
|
else |
|
plBitmap::SetGlobalLevelChopCount( 0 ); |
|
} |
|
stream.Close(); |
|
|
|
dmr = hsG3DDeviceModeRecord(selRec, selMode); |
|
} |
|
else |
|
gottaCreate = true; |
|
|
|
if( gottaCreate ) |
|
{ |
|
|
|
hsG3DDeviceSelector devSel; |
|
devSel.Enumerate(hWnd); |
|
devSel.RemoveUnusableDevModes(true); |
|
|
|
if (!devSel.GetDefault(&dmr)) |
|
{ |
|
//hsAssert(0, "plGame::LoadDevMode - No acceptable hardware found"); |
|
hsMessageBox("No suitable rendering devices found.","realMYST",hsMessageBoxNormal); |
|
return dmr; |
|
} |
|
|
|
if (stream.Open(devModeFile, "wb")) |
|
{ |
|
dmr.GetDevice()->Write(&stream); |
|
dmr.GetMode()->Write(&stream); |
|
stream.WriteSwap16((UInt16)(0*100)); |
|
stream.Close(); |
|
} |
|
|
|
} |
|
return dmr; |
|
} |
|
|
|
void plClient::ResetDisplayDevice(int Width, int Height, int ColorDepth, hsBool Windowed, int NumAASamples, int MaxAnisotropicSamples, hsBool VSync, hsBool windowOnly) |
|
{ |
|
if(!fPipeline) return; |
|
int BorderWidth = 0, BorderHeight = 0, CaptionHeight = 0; |
|
|
|
WindowActivate(false); |
|
int ActualWidth; |
|
int ActualHeight; |
|
|
|
if( Windowed ) |
|
{ |
|
BorderWidth = GetSystemMetrics( SM_CXSIZEFRAME ); |
|
BorderHeight = GetSystemMetrics( SM_CYSIZEFRAME ); |
|
CaptionHeight = GetSystemMetrics( SM_CYCAPTION ); |
|
ActualWidth = Width + BorderWidth * 2; |
|
ActualHeight = Height + BorderHeight * 2 + CaptionHeight; |
|
SetWindowLong( fWindowHndl, GWL_STYLE, |
|
WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE); |
|
SetWindowLong(fWindowHndl, GWL_EXSTYLE, 0); |
|
} |
|
else |
|
{ |
|
SetWindowLong(fWindowHndl, GWL_STYLE, |
|
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_MAXIMIZE | WS_VISIBLE); |
|
|
|
SetWindowLong(fWindowHndl, GWL_EXSTYLE, WS_EX_APPWINDOW); |
|
} |
|
|
|
if(!windowOnly) |
|
fPipeline->ResetDisplayDevice(Width, Height, ColorDepth, Windowed, NumAASamples, MaxAnisotropicSamples, VSync); |
|
|
|
float aspectratio = (float)Width / (float)Height; |
|
plMouseDevice::Instance()->SetDisplayResolution((float)Width, (float)Height); |
|
pfGameGUIMgr::GetInstance()->SetAspectRatio( aspectratio ); |
|
|
|
UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_SHOWWINDOW; |
|
if(Windowed) |
|
{ |
|
SetWindowPos( fWindowHndl, HWND_NOTOPMOST, 0, 0, ActualWidth, ActualHeight, flags ); |
|
} |
|
else |
|
{ |
|
SetWindowPos( fWindowHndl, HWND_TOP, 0, 0, Width, Height, flags ); |
|
::ClipCursor(nil); |
|
} |
|
|
|
WindowActivate(true); |
|
} |
|
|
|
|
|
void WriteBool(hsStream *stream, char *name, hsBool on ) |
|
{ |
|
char command[256]; |
|
sprintf(command, "%s %s\r\n", name, on ? "true" : "false"); |
|
stream->WriteString(command); |
|
} |
|
|
|
void WriteInt(hsStream *stream, char *name, int val ) |
|
{ |
|
char command[256]; |
|
sprintf(command, "%s %d\r\n", name, val); |
|
stream->WriteString(command); |
|
} |
|
|
|
void WriteString(hsStream *stream, const char *name, const char *val) |
|
{ |
|
char command[256]; |
|
sprintf(command, "%s %s\r\n", name, val); |
|
stream->WriteString(command); |
|
} |
|
|
|
// Detect audio/video settings and save them to their respective ini file, if ini files don't exist |
|
void plClient::IDetectAudioVideoSettings() |
|
{ |
|
// Setup default pipeline settings |
|
hsBool devmode = true; |
|
hsG3DDeviceModeRecord dmr; |
|
hsG3DDeviceSelector devSel; |
|
devSel.Enumerate(fWindowHndl); |
|
devSel.RemoveUnusableDevModes(true); |
|
|
|
if (!devSel.GetDefault(&dmr)) |
|
devmode = false; |
|
hsG3DDeviceRecord *rec = (hsG3DDeviceRecord *)dmr.GetDevice(); |
|
const hsG3DDeviceMode *mode = dmr.GetMode(); |
|
|
|
hsBool pixelshaders = rec->GetCap(hsG3DDeviceSelector::kCapsPixelShader); |
|
int psMajor = 0, psMinor = 0; |
|
rec->GetPixelShaderVersion(psMajor, psMinor); |
|
hsBool refDevice = false; |
|
if(rec->GetG3DHALorHEL() == hsG3DDeviceSelector::kHHD3DRefDev) |
|
refDevice = true; |
|
|
|
plPipeline::fDefaultPipeParams.Width = hsG3DDeviceSelector::kDefaultWidth; |
|
plPipeline::fDefaultPipeParams.Height = hsG3DDeviceSelector::kDefaultHeight; |
|
plPipeline::fDefaultPipeParams.ColorDepth = hsG3DDeviceSelector::kDefaultDepth; |
|
#if defined(HS_DEBUGGING) || defined(DEBUG) |
|
plPipeline::fDefaultPipeParams.Windowed = true; |
|
#else |
|
plPipeline::fDefaultPipeParams.Windowed = false; |
|
#endif |
|
|
|
plPipeline::fDefaultPipeParams.Shadows = 0; |
|
// enable shadows if TnL is available, meaning not an intel extreme. |
|
if(rec->GetG3DHALorHEL() == hsG3DDeviceSelector::kHHD3DTnLHalDev) |
|
plPipeline::fDefaultPipeParams.Shadows = 1; |
|
|
|
// enable planar reflections if pixelshaders are available |
|
if(pixelshaders && !refDevice) |
|
{ |
|
plPipeline::fDefaultPipeParams.PlanarReflections = 1; |
|
} |
|
else |
|
{ |
|
plPipeline::fDefaultPipeParams.PlanarReflections = 0; |
|
} |
|
|
|
// enable 2x antialiasing and anisotropic to 2 samples if pixelshader version is greater that 2.0 |
|
if(psMajor >= 2 && !refDevice) |
|
{ |
|
plPipeline::fDefaultPipeParams.AntiAliasingAmount = rec->GetMaxAnisotropicSamples() ? 2 : 0; |
|
plPipeline::fDefaultPipeParams.AnisotropicLevel = mode->GetNumFSAATypes() ? 2 : 0; |
|
} |
|
else |
|
{ |
|
plPipeline::fDefaultPipeParams.AntiAliasingAmount = 0; |
|
plPipeline::fDefaultPipeParams.AnisotropicLevel = 0; |
|
} |
|
|
|
if(refDevice) |
|
{ |
|
plPipeline::fDefaultPipeParams.TextureQuality = 0; |
|
plPipeline::fDefaultPipeParams.VideoQuality = 0; |
|
|
|
} |
|
else |
|
{ |
|
plPipeline::fDefaultPipeParams.TextureQuality = psMajor >= 2 ? 2 : 1; |
|
plPipeline::fDefaultPipeParams.VideoQuality = pixelshaders ? 2 : 1; |
|
} |
|
plPipeline::fDefaultPipeParams.VSync = false; |
|
|
|
// card specific overrides |
|
if(strstr(rec->GetDriverDesc(), "FX 5200")) |
|
{ |
|
plPipeline::fDefaultPipeParams.AntiAliasingAmount = 0; |
|
} |
|
|
|
|
|
int val = 0; |
|
hsStream *stream = nil; |
|
hsUNIXStream s; |
|
wchar audioIniFile[MAX_PATH], graphicsIniFile[MAX_PATH]; |
|
PathGetInitDirectory(audioIniFile, arrsize(audioIniFile)); |
|
StrCopy(graphicsIniFile, audioIniFile, arrsize(audioIniFile)); |
|
PathAddFilename(audioIniFile, audioIniFile, L"audio.ini", arrsize(audioIniFile)); |
|
PathAddFilename(graphicsIniFile, graphicsIniFile, L"graphics.ini", arrsize(graphicsIniFile)); |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// internal builds can use the local dir |
|
if (PathDoesFileExist(L"init//audio.ini")) |
|
StrCopy(audioIniFile, L"init//audio.ini", arrsize(audioIniFile)); |
|
if (PathDoesFileExist(L"init//graphics.ini")) |
|
StrCopy(graphicsIniFile, L"init//graphics.ini", arrsize(audioIniFile)); |
|
#endif |
|
|
|
//check to see if audio.ini exists |
|
if (s.Open(audioIniFile)) |
|
{ |
|
s.Close(); |
|
} |
|
else |
|
{ |
|
stream = plEncryptedStream::OpenEncryptedFileWrite(audioIniFile); |
|
|
|
plAudioCaps caps = plAudioCapsDetector::Detect(false, true); |
|
val = 6; |
|
if( (hsPhysicalMemory() < 256) || plProfileManager::Instance().GetProcessorSpeed() < 1350000000) |
|
{ |
|
val = 3; |
|
} |
|
|
|
char deviceName[256]; |
|
sprintf(deviceName, "\"%s\"", DEFAULT_AUDIO_DEVICE_NAME); |
|
|
|
WriteBool(stream, "Audio.Initialize", caps.IsAvailable()); |
|
WriteBool(stream, "Audio.UseEAX", false); |
|
WriteInt(stream, "Audio.SetPriorityCutoff", val); |
|
WriteInt(stream, "Audio.MuteAll", false); |
|
WriteInt(stream, "Audio.SetChannelVolume SoundFX", 1); |
|
WriteInt(stream, "Audio.SetChannelVolume BgndMusic", 1); |
|
WriteInt(stream, "Audio.SetChannelVolume Ambience", 1); |
|
WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1); |
|
WriteInt(stream, "Audio.EnableVoiceRecording", 1); |
|
WriteString(stream, "Audio.SetDeviceName", deviceName ); |
|
stream->Close(); |
|
delete stream; |
|
stream = nil; |
|
} |
|
|
|
// check to see if graphics.ini exists |
|
if (s.Open(graphicsIniFile)) |
|
{ |
|
s.Close(); |
|
} |
|
else |
|
{ |
|
IWriteDefaultGraphicsSettings(graphicsIniFile); |
|
} |
|
} |
|
|
|
void plClient::IWriteDefaultGraphicsSettings(const wchar* destFile) |
|
{ |
|
hsStream *stream = plEncryptedStream::OpenEncryptedFileWrite(destFile); |
|
|
|
WriteInt(stream, "Graphics.Width", plPipeline::fDefaultPipeParams.Width); |
|
WriteInt(stream, "Graphics.Height", plPipeline::fDefaultPipeParams.Height); |
|
WriteInt(stream, "Graphics.ColorDepth", plPipeline::fDefaultPipeParams.ColorDepth); |
|
WriteBool(stream, "Graphics.Windowed", plPipeline::fDefaultPipeParams.Windowed); |
|
WriteInt(stream, "Graphics.AntiAliasAmount", plPipeline::fDefaultPipeParams.AntiAliasingAmount); |
|
WriteInt(stream, "Graphics.AnisotropicLevel", plPipeline::fDefaultPipeParams.AnisotropicLevel ); |
|
WriteInt(stream, "Graphics.TextureQuality",plPipeline::fDefaultPipeParams.TextureQuality); |
|
WriteInt(stream, "Quality.Level", plPipeline::fDefaultPipeParams.VideoQuality); |
|
WriteInt(stream, "Graphics.Shadow.Enable", plPipeline::fDefaultPipeParams.Shadows); |
|
WriteInt(stream, "Graphics.EnablePlanarReflections", plPipeline::fDefaultPipeParams.PlanarReflections); |
|
WriteBool(stream, "Graphics.EnableVSync", plPipeline::fDefaultPipeParams.VSync); |
|
stream->Close(); |
|
delete stream; |
|
stream = nil; |
|
} |
|
|
|
|
|
void plClient::WindowActivate(bool active) |
|
{ |
|
if (GetDone()) |
|
return; |
|
|
|
if( !fWindowActive != !active ) |
|
{ |
|
if( fInputManager != nil ) |
|
fInputManager->Activate( active ); |
|
|
|
plArmatureMod::WindowActivate( active ); |
|
} |
|
fWindowActive = active; |
|
} |
|
|
|
|
|
//============================================================================ |
|
void plClient::IOnAsyncInitComplete () { |
|
// Init State Desc Language (files should now be downloaded and in place) |
|
plSDLMgr::GetInstance()->SetNetApp(plNetClientMgr::GetInstance()); |
|
plSDLMgr::GetInstance()->Init( plSDL::kDisallowTimeStamping ); |
|
|
|
PythonInterface::initPython(); |
|
// set the pipeline for the python cyMisc module so that it can do a screen capture |
|
cyMisc::SetPipeline( fPipeline ); |
|
|
|
// Load our custom fonts from our current dat directory |
|
fFontCache->LoadCustomFonts("dat"); |
|
plWinFontCache::GetInstance().LoadCustomFonts("dat"); |
|
|
|
// We'd like to do a SetHoldLoadRequests here, but the GUI stuff doesn't draw right |
|
// if you try to delay the loading for it. To work around that, we allocate a |
|
// global loading bar in advance and set it to a big enough range that when the GUI's |
|
// are done loading about the right amount of it is filled. |
|
fNumLoadingRooms++; |
|
IStartProgress("Loading Global...", 0); |
|
|
|
/// Init the KI |
|
pfGameGUIMgr *mgr = pfGameGUIMgr::GetInstance(); |
|
mgr->LoadDialog( "KIBlackBar" ); // load the blackbar which will bootstrap in the rest of the KI dialogs |
|
|
|
// Init the journal book API |
|
pfJournalBook::SingletonInit(); |
|
|
|
SetHoldLoadRequests(true); |
|
fProgressBar->SetLength(fProgressBar->GetProgress()); |
|
|
|
plClothingMgr::Init(); |
|
// Load in any clothing data |
|
((plResManager*)hsgResMgr::ResMgr())->PageInAge("GlobalClothing"); |
|
|
|
pfMarkerMgr::Instance(); |
|
|
|
fAnimDebugList = TRACKED_NEW plAnimDebugList(); |
|
|
|
/// Now parse final init files (*.fni). These are files just like ini files, only to be run |
|
/// after all hell has broken loose in the client. |
|
wchar initFolder[MAX_PATH]; |
|
PathGetInitDirectory(initFolder, arrsize(initFolder)); |
|
pfConsoleDirSrc dirSrc( fConsoleEngine, initFolder, L"net*.fni" ); // connect to net first |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// internal builds also parse the local init folder |
|
dirSrc.ParseDirectory( L"init", L"net*.fni" ); |
|
#endif |
|
|
|
dirSrc.ParseDirectory( initFolder, L"*.fni" ); |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// internal builds also parse the local init folder |
|
dirSrc.ParseDirectory( L"init", L"*.fni" ); |
|
#endif |
|
|
|
// run fni in the Aux Init dir |
|
if (fpAuxInitDir) |
|
{ |
|
dirSrc.ParseDirectory(fpAuxInitDir, "net*.fni" ); // connect to net first |
|
dirSrc.ParseDirectory(fpAuxInitDir, "*.fni" ); |
|
} |
|
|
|
fNumLoadingRooms--; |
|
|
|
((plResManager*)hsgResMgr::ResMgr())->PageInAge("GlobalAnimations"); |
|
SetHoldLoadRequests(false); |
|
|
|
// Tell the transition manager to start faded out. This is so we don't |
|
// get a frame or two of non-faded drawing before we do our initial fade in |
|
(void)(TRACKED_NEW plTransitionMsg( plTransitionMsg::kFadeOut, 0.0f, true ))->Send(); |
|
|
|
fFlags.SetBit(kFlagAsyncInitComplete); |
|
if (fFlags.IsBitSet(kFlagGlobalDataLoaded)) |
|
ICompleteInit(); |
|
} |
|
|
|
//============================================================================ |
|
void plClient::ICompleteInit () { |
|
// Reset clear color on the pipeline |
|
// fPipeline->ClearRenderTarget( &fClearColor, &depth ); |
|
|
|
plSimulationMgr::GetInstance()->Resume(); // start the sim at the last possible minute |
|
|
|
fFlags.SetBit( kFlagIniting, false ); |
|
hsStatusMessage("Client init complete."); |
|
|
|
// Tell everyone we're ready to rock. |
|
plClientMsg* clientMsg = TRACKED_NEW plClientMsg(plClientMsg::kInitComplete); |
|
clientMsg->SetBCastFlag(plMessage::kBCastByType); |
|
clientMsg->Send(); |
|
|
|
CsrSrvInitialize(); |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IHandlePreloaderMsg (plPreloaderMsg * msg) { |
|
|
|
plgDispatch::Dispatch()->UnRegisterForExactType(plPreloaderMsg::Index(), GetKey()); |
|
|
|
if (!msg->fSuccess) { |
|
char str[1024]; |
|
StrPrintf( |
|
str, |
|
arrsize(str), |
|
"Secure file preloader failed" |
|
); |
|
plNetClientApp::GetInstance()->QueueDisableNet(true, str); |
|
return; |
|
} |
|
|
|
fPatchGlobalAges = true; |
|
} |
|
|
|
//============================================================================ |
|
void plClient::IHandleNetCommAuthMsg (plNetCommAuthMsg * msg) { |
|
|
|
plgDispatch::Dispatch()->UnRegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); |
|
|
|
if (IS_NET_ERROR(msg->result)) { |
|
char str[1024]; |
|
StrPrintf( |
|
str, |
|
arrsize(str), |
|
// fmt |
|
"Authentication failed: NetError %u, %S.\n" |
|
,// values |
|
msg->result, |
|
NetErrorToString(msg->result) |
|
); |
|
plNetClientApp::GetInstance()->QueueDisableNet(true, str); |
|
return; |
|
} |
|
|
|
plgDispatch::Dispatch()->RegisterForExactType(plPreloaderMsg::Index(), GetKey()); |
|
|
|
// Precache our secure files |
|
pfSecurePreloader::GetInstance()->RequestFileGroup(L"Python", L"pak"); |
|
pfSecurePreloader::GetInstance()->RequestFileGroup(L"SDL", L"sdl"); |
|
pfSecurePreloader::GetInstance()->Start(); |
|
}
|
|
|