int main(int argc, _TCHAR* argv[]) { GameBase *Juego; Juego = new TP4(800,600,"TP Final"); Juego->Loop(); delete Juego; return 0; }
void HifiClientProcessList::ageTickCache(S32 numToAge, S32 len) { for (ProcessObject * pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase(pobj); if ( obj && obj->getTypeMask() & GameBaseHiFiObjectType ) obj->getTickCache().ageCache(numToAge,len); } }
int main(int argc, _TCHAR* argv[]) { GameBase *Juego; Juego = new TP2(800,600,"U3 EJ 3"); Juego->Loop(); delete Juego; return 0; }
void MainMenuState::cleanup(GameBase &game) { delete _menu; _menu = nullptr; delete _advertismentList; _advertismentList = nullptr; game.getEngine()->getDrawEngine()->unloadAll(); game.getEngine()->getInputEngine()->clearBindings(); }
void RPGBase::onRemove() { GameBase * pCaster = dynamic_cast<GameBase *>( Sim::findObject(mCasterSimID) ); if (pCaster) { pCaster->removeRPGBase(this); } removeFromScene(); Parent::onRemove(); }
void MainMenuState::handleEvents(GameBase &game, GameTime &gameTime) { SDL_Event event; while (SDL_PollEvent(&event)) { game.getEngine()->getInputEngine()->handleEvent(event); switch (event.type) { case SDLK_ESCAPE: game.stop(); break; case SDL_CONTROLLERBUTTONDOWN: switch (event.cbutton.button) { case SDL_CONTROLLER_BUTTON_A: _menu->doAction(); break; case SDL_CONTROLLER_BUTTON_B: game.stop(); case SDL_CONTROLLER_BUTTON_DPAD_UP: _menu->selectPrevious(); break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: _menu->selectNext(); break; } break; case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_DOWN: case 1: if (_menu) _menu->selectNext(); //game.getEngine()->getAudioEngine()->play("menu_switch_effect", 0); break; case SDLK_UP: case 0: if (_menu) _menu->selectPrevious(); //game.getEngine()->getAudioEngine()->play("menu_switch_effect", 0); break; case SDLK_KP_ENTER: case SDLK_RETURN: case 10: if (_menu) _menu->doAction(); break; } } } }
void GameBase::onUnmount( SceneObject *obj, S32 node ) { clearNotify(obj); GameBase *gbaseObj = dynamic_cast<GameBase*>( obj ); if ( gbaseObj && gbaseObj->getControlObject() != this ) clearProcessAfter(); if (!isGhost()) { setMaskBits(MountedMask); mDataBlock->onUnmount_callback( this, obj, node ); } }
void GameOverState::redraw(GameBase &game) { game.getEngine()->getDrawEngine()->prepareForDraw(); game.getEngine()->getDrawEngine()->draw("gameoverbackground"); game.getEngine()->getDrawEngine()->draw("winner", 190, 190); for (int i = 1; i <= _characterCount; i++) { game.getEngine()->getDrawEngine()->drawText("rank" + std::to_string(i), 717, 280 + (i * 75)); } if (_isLoaded) _menu->draw(&game); game.getEngine()->getDrawEngine()->render(); }
void WaterObject::updateUnderwaterEffect( SceneRenderState *state ) { AssertFatal( isClientObject(), "uWaterObject::updateUnderwaterEffect() called on the server" ); PostEffect *effect = getUnderwaterEffect(); if ( !effect ) return; // Never use underwater postFx with Basic Lighting, we don't have depth. if ( mBasicLighting ) { effect->disable(); return; } GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; GameBase *control = conn->getControlObject(); if ( !control ) return; WaterObject *water = control->getCurrentWaterObject(); if ( water == NULL ) effect->disable(); else if ( water == this ) { MatrixF mat; conn->getControlCameraTransform( 0, &mat ); if ( mUnderwater ) { effect->enable(); effect->setOnThisFrame( true ); mWaterFogData.depthGradMax = mDepthGradientMax; state->getSceneManager()->setWaterFogData( mWaterFogData ); // Register our depthGradient texture with a name so it can // be fetched by the effect when it renders. if ( !mNamedDepthGradTex.isRegistered() ) mNamedDepthGradTex.registerWithName( "waterDepthGradMap" ); mNamedDepthGradTex.setTexture( mDepthGradientTex ); } else effect->disable(); } }
void Trigger::processTick(const Move* move) { Parent::processTick(move); if (!mDataBlock) return; if (mDataBlock->isClientSide && isServerObject()) return; if (!mDataBlock->isClientSide && isClientObject()) return; // if (mObjects.size() == 0) return; if (mLastThink + mDataBlock->tickPeriodMS < mCurrTick) { mCurrTick = 0; mLastThink = 0; for (S32 i = S32(mObjects.size() - 1); i >= 0; i--) { if (testObject(mObjects[i]) == false) { GameBase* remove = mObjects[i]; mObjects.erase(i); clearNotify(remove); if (!mLeaveCommand.isEmpty()) { String command = String("%obj = ") + remove->getIdString() + ";" + mLeaveCommand; Con::evaluate(command.c_str()); } mDataBlock->onLeaveTrigger_callback( this, remove ); } } if (!mTickCommand.isEmpty()) Con::evaluate(mTickCommand.c_str()); if (mObjects.size() != 0) mDataBlock->onTickTrigger_callback( this ); } else { mCurrTick += TickMs; } }
void GameBase::onMount( SceneObject *obj, S32 node ) { deleteNotify( obj ); // Are we mounting to a GameBase object? GameBase *gbaseObj = dynamic_cast<GameBase*>( obj ); if ( gbaseObj && gbaseObj->getControlObject() != this ) processAfter( gbaseObj ); if (!isGhost()) { setMaskBits(MountedMask); mDataBlock->onMount_callback( this, obj, node ); } }
bool RPGBase::onAdd() { if (!Parent::onAdd()) return(false); addToScene(); GameBase * pCaster = dynamic_cast<GameBase *>( Sim::findObject(mCasterSimID) ); if (pCaster) { pCaster->pushRPGBase(this); } return(true); }
void MainMenuState::draw(GameBase &game, GameTime &gameTime) { game.getEngine()->getDrawEngine()->prepareForDraw(); game.getEngine()->getDrawEngine()->draw("mainmenu_background"); game.getEngine()->getDrawEngine()->drawText("maintitle", 50, 70); //game.getEngine()->getDrawEngine()->draw("menu_play", 585, 243); game.getEngine()->getDrawEngine()->draw("advertisement", _advertisementX, _advertisementY); if (_advertisementIndex >= 0) //game.getEngine()->getDrawEngine()->draw("advertisement", _advertisementX, _advertisementY); _menu->draw(&game); game.getEngine()->getDrawEngine()->render(); }
bool GameBase::setDataBlockProperty( void *obj, const char *index, const char *db) { if( db == NULL || !db || !db[ 0 ] ) { Con::errorf( "GameBase::setDataBlockProperty - Can't unset datablock on GameBase objects" ); return false; } GameBase* object = static_cast< GameBase* >( obj ); GameBaseData* data; if( Sim::findObject( db, data ) ) return object->setDataBlock( data ); Con::errorf( "GameBase::setDatablockProperty - Could not find data block \"%s\"", db ); return false; }
void MainMenuState::update(GameBase &game, GameTime &gameTime) { game.getEngine()->getInputEngine()->update(game); if (_advertisementIndex >= 0.0f && _shouldRefreshAdvertisement) { int timeSinceLastUpdate = game.getGameTime()->getElapsedSinceLastUpdate() / 1000.0f; if (timeSinceLastUpdate >= 0.0f) { if ((_lastTimeSinceAdvertisementChange += timeSinceLastUpdate) >= _advertisementRefreshRate) { loadAdvertisement(); _lastTimeSinceAdvertisementChange = 0.0f; } } } }
void FlyingCamera::updateGUIInfo() { GameBase *player; PlayerManager::ClientRep *rep; SimGui::TSControl *gui; SimGui::SimpleText *txtModCtrl, *txtObjCtrl; gui = dynamic_cast<SimGui::TSControl *> (manager->findObject(szGUIObjName)); if (gui) { txtModCtrl = dynamic_cast<SimGui::SimpleText *> (gui->findControlWithTag(IDCTG_OBSERVER_CURMOD)); if (txtModCtrl) { txtModCtrl->setText("OBSERVER MODE"); } txtObjCtrl = dynamic_cast<SimGui::SimpleText *> (gui->findControlWithTag(IDCTG_OBSERVER_CUROBJ)); if (txtObjCtrl) { if (objFollow) { player = dynamic_cast<GameBase *>(objFollow); if (player && (rep = cg.playerManager->findClient(player->getOwnerClient())) != NULL && strlen(rep->name)) { txtObjCtrl->setText(rep->name); } else { txtObjCtrl->setText("Follow Mode"); } } else { txtObjCtrl->setText("Free Camera"); } } } }
void ForestWindEmitter::_renderEmitterInfo( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { if ( overrideMat ) return; GFXTransformSaver saver; GFXDrawUtil *drawer = GFX->getDrawUtil(); AssertFatal( drawer, "Got NULL GFXDrawUtil!" ); const Point3F &pos = getPosition(); const VectorF &windVec = mWind->getDirection(); GFXStateBlockDesc desc; desc.setBlend( true ); desc.setZReadWrite( true, false ); // Draw an arrow pointing // in the wind direction. drawer->drawArrow( desc, pos, pos + (windVec * mWindStrength), ColorI( 0, 0, 255, 255 ) );//Point3F( -235.214, 219.589, 34.0991 ), Point3F( -218.814, 244.731, 37.5587 ), ColorI( 255, 255, 0, 255 ) );// drawer->drawArrow( desc, pos, pos + (mWind->getTarget() * mWindStrength ), ColorI( 255, 0, 0, 85 ) ); S32 useRadius = mWindRadius; // Draw a 2D circle for the wind radius. if ( isRadialEmitter() ) { //WLE - Vince //So the problem is that when your inside the sphere it won't render so it might make someone //think that it's not working right. So what I did was determine if the camera is inside the sphere. //If the camera is inside the sphere, then I find the distance from the center of the sphere to the camera //Round down and use that as the radius to draw the sphere. //That way if someone zooms in or out, their screen is still showing the sphere. GameConnection * gc = GameConnection::getConnectionToServer(); GameBase* gb = gc->getCameraObject(); if (gb) { Point3F camPos = gb->getPosition(); if ( getPosition().isInsideSphere( camPos, mWindRadius ) ) useRadius = getPosition().distanceTo(camPos); } drawer->drawSphere( desc, useRadius, pos, ColorI( 255, 0, 0, 80 ) ); } }
void CreateLevelState::draw(GameBase &game, GameTime &gameTime) { game.getEngine()->getDrawEngine()->prepareForDraw(); game.getEngine()->getDrawEngine()->draw("create_background"); game.getEngine()->getDrawEngine()->drawText("createtitle", 50, 75); int x = (game.getEngine()->getDrawEngine()->getWindowWidth() - 600) / 2; game.getEngine()->getDrawEngine()->drawRectangle(Rectangle(x, 250, 600, 80), 102, 175, 207); game.getEngine()->getDrawEngine()->drawDynamicText("input", *_name, x + 20, 260); if (!_error->empty()) { auto size = game.getEngine()->getDrawEngine()->getTextSize(*_error); int errX = (game.getEngine()->getDrawEngine()->getWindowWidth() - size[0]) / 2; game.getEngine()->getDrawEngine()->drawText(*_error, errX, 210); } _menu->draw(&game); game.getEngine()->getDrawEngine()->render(); }
void ForestWindEmitter::_renderEmitterInfo( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { if ( overrideMat ) return; GFXTransformSaver saver; GFXDrawUtil *drawer = GFX->getDrawUtil(); AssertFatal( drawer, "Got NULL GFXDrawUtil!" ); const Point3F &pos = getPosition(); const VectorF &windVec = mWind->getDirection(); GFXStateBlockDesc desc; desc.setBlend( true ); desc.setZReadWrite( true, false ); // Draw an arrow pointing // in the wind direction. drawer->drawArrow( desc, pos, pos + (windVec * mWindStrength), ColorI( 0, 0, 255, 255 ) );//Point3F( -235.214, 219.589, 34.0991 ), Point3F( -218.814, 244.731, 37.5587 ), ColorI( 255, 255, 0, 255 ) );// drawer->drawArrow( desc, pos, pos + (mWind->getTarget() * mWindStrength ), ColorI( 255, 0, 0, 85 ) ); S32 useRadius = mWindRadius; // Draw a 2D circle for the wind radius. if ( isRadialEmitter() ) { // If the camera is close to the sphere, shrink the sphere so it remains visible. GameConnection* gc = GameConnection::getConnectionToServer(); GameBase* gb; if ( gc && (gb = gc->getCameraObject()) ) { F32 camDist = (gb->getPosition() - getPosition()).len(); if ( camDist < mWindRadius ) useRadius = camDist; } drawer->drawSphere( desc, useRadius, pos, ColorI( 255, 0, 0, 80 ) ); } }
void GameOverState::handleEvents(GameBase &game, GameTime &gameTime) { SDL_Event event; while (SDL_PollEvent(&event)) { game.getEngine()->getInputEngine()->getMouse().handleMouseEvent(event); if (event.type == SDL_KEYDOWN) { switch (event.key.keysym.sym) { case SDLK_DOWN: if (_isLoaded) _menu->selectNext(); break; case SDLK_UP: if (_isLoaded) _menu->selectPrevious(); break; case SDLK_KP_ENTER: case SDLK_RETURN: if (_isLoaded) _menu->doAction(); break; } } else if (event.type == SDL_CONTROLLERBUTTONDOWN) { switch (event.cbutton.button) { case SDL_CONTROLLER_BUTTON_A: if (_isLoaded) _menu->doAction(); break; case SDL_CONTROLLER_BUTTON_DPAD_UP: if (_isLoaded) _menu->selectPrevious(); break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: if (_isLoaded) _menu->selectNext(); break; } } } }
void CreateLevelState::handleEvents(GameBase &game, GameTime &gameTime) { SDL_Event event; while (SDL_PollEvent(&event)) { game.getEngine()->getInputEngine()->handleEvent(event); if (event.type == SDL_KEYDOWN) { switch (event.key.keysym.sym) { case SDLK_BACKSPACE: if (_name->size() > 0) _name->pop_back(); break; case SDLK_SPACE: *_name += " "; break; case SDLK_DOWN: _menu->selectNext(); break; case SDLK_UP: _menu->selectPrevious(); break; case SDLK_RETURN: _menu->doAction(); break; default: if (_name->size() <= 18) { std::string input = SDL_GetKeyName(event.key.keysym.sym); if (input.size() == 1 && input[0] >= 'A' && input[0] <= 'Z') { *_name += _name->size() == 0 ? input[0] : tolower(input[0]); } } break; } } } }
void CreateLevelState::init(GameBase &game) { _name = new std::string(); _game = &game; _error = new std::string(); game.getEngine()->getDrawEngine()->loadText("createtitle", "Enter a name for your new level", { 255, 255, 255 }, "trebucbd", 48); game.getEngine()->getDrawEngine()->loadText("existserr", "There already exists a level with this name.", { 217, 13, 13 }, "trebucbd", 20); game.getEngine()->getDrawEngine()->loadText("invaliderr", "Enter a name for your new level.", { 217, 13, 13 }, "trebucbd", 20); game.getEngine()->getDrawEngine()->loadDynamicText("input", { 255, 255, 255 }, "trebucbd", 48); game.getEngine()->getDrawEngine()->load("create_background", "assets/screens/mainmenu"); //std::function<void(MenuItem *item)> callBack = &MainMenuState::menuAction; _menu = new Menu(453, 360, game); _menu->addMenuTextItem("Create", (std::function<void()>)std::bind(&CreateLevelState::create, this)); _menu->addMenuTextItem("Cancel", (std::function<void()>)[&] { _game->getStateManager()->pushState(LevelSelectionState::getInstance()); }); game.getEngine()->getInputEngine()->setMouseEnabled(); }
bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareState *flareState, U32 *outVisDelta, F32 *outOcclusionFade, Point3F *outLightPosSS) { // Reflections use the results from the last forward // render so we don't need multiple queries. if ( state->isReflectPass() ) { *outOcclusionFade = flareState->occlusion; *outVisDelta = Sim::getCurrentTime() - flareState->visChangedTime; return flareState->visible; } // Initialize it to something first. *outOcclusionFade = 0; // First check to see if the flare point // is on scren at all... if not then return // the last result. const Point3F &lightPos = flareState->lightMat.getPosition(); const RectI &viewport = GFX->getViewport(); MatrixF projMatrix; state->getCameraFrustum().getProjectionMatrix(&projMatrix); if( state->isReflectPass() ) projMatrix = state->getSceneManager()->getNonClipProjection(); bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix ); // It is onscreen, so raycast as a simple occlusion test. const LightInfo *lightInfo = flareState->lightInfo; const bool isVectorLight = lightInfo->getType() == LightInfo::Vector; const bool useOcclusionQuery = isVectorLight ? flareState->worldRadius > 0.0f : mOcclusionRadius > 0.0f; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( useOcclusionQuery ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onScreen = true; needsRaycast = false; // Test the hardware queries for rendered pixels. U32 pixels = 0, fullPixels = 0; GFXOcclusionQuery::OcclusionQueryStatus status; flareState->occlusionQuery.getLastStatus( false, &status, &pixels ); flareState->fullPixelQuery.getLastStatus( false, NULL, &fullPixels ); if ( status == GFXOcclusionQuery::NotOccluded && fullPixels != 0 ) *outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f ); if( !flareState->occlusionQuery.isWaiting() ) { // Setup the new queries. RenderPassManager *rpm = state->getRenderPass(); OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>(); ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery.getQuery(); ri->query2 = flareState->fullPixelQuery.getQuery(); ri->isSphere = true; ri->position = lightPos; if ( isVectorLight && flareState->worldRadius > 0.0f ) ri->scale.set( flareState->worldRadius ); else ri->scale.set( mOcclusionRadius ); ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() ); // Submit the queries. state->getRenderPass()->addInst( ri ); } } const Point3F &camPos = state->getCameraPosition(); if ( needsRaycast ) { // Use a raycast to determine occlusion. GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return false; const bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( !gClientContainer.castRay( camPos, lightPos, LosMask, &rayInfo ) ) *outOcclusionFade = 1.0f; if ( control && fps ) control->enableCollision(); } // The raycast and hardware occlusion query only calculate if // the flare is on screen... if does not account for being // partially offscreen. // // The code here clips a box against the viewport to // get an approximate percentage of onscreen area. // F32 worldRadius = flareState->worldRadius > 0 ? flareState->worldRadius : mOcclusionRadius; if ( worldRadius > 0.0f ) { F32 dist = ( camPos - lightPos ).len(); F32 pixelRadius = state->projectRadius(dist, worldRadius); RectI visRect( outLightPosSS->x - pixelRadius, outLightPosSS->y - pixelRadius, pixelRadius * 2.0f, pixelRadius * 2.0f ); F32 fullArea = visRect.area(); if ( visRect.intersect( viewport ) ) { F32 visArea = visRect.area(); *outOcclusionFade *= visArea / fullArea; onScreen = true; } else *outOcclusionFade = 0.0f; } const bool lightVisible = onScreen && *outOcclusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. const U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Return the visibility delta for time fading. *outVisDelta = currentTime - flareState->visChangedTime; // Store the final occlusion fade so that it can // be used in reflection rendering later. flareState->occlusion = *outOcclusionFade; return lightVisible; }
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); // No elements then nothing to render. if ( mElementCount == 0 ) return; // We need these all over the place later. const Point3F &camPos = state->getCameraPosition(); const RectI &viewport = GFX->getViewport(); const Point3F &lightPos = flareState->lightMat.getPosition(); LightInfo *lightInfo = flareState->lightInfo; bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Perform visibility testing on the light... // Project the light position from world to screen space, we need this // position later, and it tells us if it is actually onscreen. Point3F lightPosSS; bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() ); U32 visDelta = U32_MAX; U32 fadeOutTime = 20; U32 fadeInTime = 125; // Fade factor based on amount of occlusion. F32 occlusionFade = 1.0f; bool lightVisible = true; if ( !state->isReflectPass() ) { // It is onscreen, so raycast as a simple occlusion test. U32 losMask = STATIC_COLLISION_MASK | ShapeBaseObjectType | StaticTSObjectType | ItemObjectType | PlayerObjectType; GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( flareState->occlusionQuery == NULL ) flareState->occlusionQuery = GFX->createOcclusionQuery(); if ( flareState->fullPixelQuery == NULL ) flareState->fullPixelQuery = GFX->createOcclusionQuery(); if ( flareState->occlusionQuery && ( ( isVectorLight && flareState->worldRadius > 0.0f ) || ( !isVectorLight && mOcclusionRadius > 0.0f ) ) ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onscreen = true; U32 pixels = -1; GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); String str = flareState->occlusionQuery->statusToString( status ); Con::setVariable( "$Flare::OcclusionStatus", str.c_str() ); Con::setIntVariable( "$Flare::OcclusionVal", pixels ); if ( status == GFXOcclusionQuery::Occluded ) occlusionFade = 0.0f; if ( status != GFXOcclusionQuery::Unset ) needsRaycast = false; RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); Point3F scale( Point3F::One ); if ( isVectorLight && flareState->worldRadius > 0.0f ) scale *= flareState->worldRadius; else scale *= mOcclusionRadius; ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery; ri->query2 = flareState->fullPixelQuery; ri->position = lightPos; ri->scale = scale; ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() ); ri->isSphere = true; state->getRenderPass()->addInst( ri ); if ( status == GFXOcclusionQuery::NotOccluded ) { U32 fullPixels; flareState->fullPixelQuery->getStatus( true, &fullPixels ); occlusionFade = (F32)pixels / (F32)fullPixels; // Approximation of the full pixel count rather than doing // two queries, but it is not very accurate. /* F32 dist = ( camPos - lightPos ).len(); F32 radius = scale.x; radius = ( radius / dist ) * state->getWorldToScreenScale().y; occlusionFade = (F32)pixels / (4.0f * radius * radius); occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f ); */ } } Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade ); if ( needsRaycast ) { // Use a raycast to determine occlusion. bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) ) occlusionFade = 0.0f; if ( control && fps ) control->enableCollision(); } lightVisible = onscreen && occlusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Save this in the state so that we have it during the reflect pass. flareState->occlusion = occlusionFade; visDelta = currentTime - flareState->visChangedTime; } else // state->isReflectPass() { occlusionFade = flareState->occlusion; lightVisible = flareState->visible; visDelta = Sim::getCurrentTime() - flareState->visChangedTime; } // We can only skip rendering if the light is not visible, and it // has elapsed the fadeOutTime. if ( !lightVisible && visDelta > fadeOutTime ) return; // In a reflection we only render the elements with zero distance. U32 elementCount = mElementCount; if ( state->isReflectPass() ) { elementCount = 0; for ( ; elementCount < mElementCount; elementCount++ ) { if ( mElementDist[elementCount] > 0.0f ) break; } } if ( elementCount == 0 ) return; // A bunch of preparatory math before generating verts... const Point2I &vpExtent = viewport.extent; Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f ); Point2I halfViewportExtentI( viewport.extent / 2 ); Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f ); Point3F screenCenter( 0,0,0 ); Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f ); lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; Point3F flareVec( screenCenter - lightPosSS ); F32 flareLength = flareVec.len(); flareVec.normalizeSafe(); Point3F basePoints[4]; basePoints[0] = Point3F( -0.5, 0.5, 0.0 ); basePoints[1] = Point3F( -0.5, -0.5, 0.0 ); basePoints[2] = Point3F( 0.5, -0.5, 0.0 ); basePoints[3] = Point3F( 0.5, 0.5, 0.0 ); Point3F rotatedBasePoints[4]; rotatedBasePoints[0] = basePoints[0]; rotatedBasePoints[1] = basePoints[1]; rotatedBasePoints[2] = basePoints[2]; rotatedBasePoints[3] = basePoints[3]; Point3F fvec( -1, 0, 0 ); F32 rot = mAcos( mDot( fvec, flareVec ) ); Point3F rvec( 0, -1, 0 ); rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f; vectorRotateZAxis( rotatedBasePoints[0], rot ); vectorRotateZAxis( rotatedBasePoints[1], rot ); vectorRotateZAxis( rotatedBasePoints[2], rot ); vectorRotateZAxis( rotatedBasePoints[3], rot ); // Here we calculate a the light source's influence on the effect's size // and brightness... // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; // Scale based on world space distance from camera to light source. F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f; // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < fadeInTime && flareState->occlusion ) fadeInOutScale = (F32)visDelta / (F32)fadeInTime; else if ( !lightVisible && visDelta < fadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; // The baseColor which modulates the color of all elements. ColorF baseColor; if ( flareState->fullBrightness == 0.0f ) baseColor = ColorF::BLACK; else // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Fill in the vertex buffer... const U32 vertCount = 4 * elementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *pVert = flareState->vertBuffer.lock(); const Point2I &widthHeightI = mFlareTexture.getWidthHeight(); Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y ); for ( U32 i = 0; i < elementCount; i++ ) { Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints; ColorF elementColor( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) elementColor *= lightInfo->getColor(); Point3F elementPos; elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength; elementPos.z = 0.0f; F32 maxDist = 1.5f; F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) ); F32 distanceScale = ( maxDist - elementDist ) / maxDist; distanceScale = 1.0f; const RectF &elementRect = mElementRect[i]; Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f ); elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale; if ( elementSize.x < 100.0f ) { F32 alphaScale = mPow( elementSize.x / 100.0f, 2 ); elementColor *= alphaScale; } elementColor.clamp(); Point2F texCoordMin, texCoordMax; texCoordMin = elementRect.point * oneOverTexSize; texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize; pVert->color = elementColor; pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMin.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMin.y ); pVert++; } flareState->vertBuffer.unlock(); // Create and submit the render instance... RenderPassManager *renderManager = state->getRenderPass(); ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->type = RenderPassManager::RIT_Particle; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = ri->modelViewProj; ri->count = elementCount; // Only draw the light flare in high-res mode, never off-screen mode ri->systemState = ParticleRenderInst::AwaitingHighResDraw; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = &*(mFlareTexture); ri->softnessDistance = 1.0f; // Sort by texture too. ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; renderManager->addInst( ri ); }
bool Player::detectItem(GameBase *obj) { // See if our fov has changed ... saves a couple of trig ops if(!fov) return false; if (old_fov != fov) { cos_fov = m_cos(fov / 2); tan_fov = tan(fov / 2); old_fov = fov; } // Cast from either ourselves or the object we are controlling. PlayerManager::ClientRep *me = sg.playerManager->findClient(getOwnerClient()); if(!me) return false; GameBase* src = me->controlObject; if(!src) return false; // Get the object's position in player space TMat3F mat, inv; mat = src->getEyeTransform(); inv = mat; inv.inverse(); const Box3F &box = obj->getBoundingBox(); Vector3F distance, objPos = (box.fMin + box.fMax) * 0.5f; m_mul(objPos, inv, &distance); // Get the angle between the object and the Y axis, see if that // angle is less than our FOV angle -- if so, the object is // within our FOV float rDistance = distance.len(); if(rDistance < 1) return true; float cos_theta = distance.y / rDistance; if (cos_theta >= cos_fov) { // Second check: see if the object's projected size is // large enough for us to see (converting projected size // into percentage-of-screen-size) float size = max(box.fMax.z - box.fMin.z, box.fMax.x - box.fMin.x); float p_size = size / (rDistance * tan_fov); // Multiply the projected size of the object by its haze factor // to see if we can really "see" it -- in essence, this means // that the hazier an object gets, the bigger it will need to // be for you to see it (pretty sensible) if ((p_size * (1.0f - detectHazeFactor * obj->getHaze(mat.p))) > detectMinSize) { /* // Now check its velocity ... this should be thresholded // to some range-of-motion ... #define MIN_DETECT_VELOCITY 1.0f // should be made a member var if (obj->getLinearVelocity().lenf() >= MIN_DETECT_VELOCITY) { */ // Build query SimContainerQuery query; query.id = src->getId(); query.type = -1; query.mask = SimTerrainObjectType | SimInteriorObjectType | StaticObjectType | VehicleObjectType | MoveableObjectType; query.detail = SimContainerQuery::DefaultDetail; query.box.fMin = mat.p; // Shoot from the eye query.box.fMax = objPos; // See if we can see the object SimCollisionInfo info; SimContainer *root = findObject(manager, SimRootContainerId, root); root->findLOS(query, &info); return !info.object || info.object == obj; /* } */ } } return (false); }
static void CreateServerMark(CLIENTWEAPONFX & theStruct) { AMMO* pAmmo = g_pWeaponMgr->GetAmmo(theStruct.nAmmoId); if (!pAmmo) return; // If this isn't a GameBase object, return... if (!IsGameBase(theStruct.hObj)) return; // See if we should create a mark, or simply move one of the GameBase's // marks. // If the GameBase has the max number of marks or this mark is very close // to a pre-existing mark, just move that mark to the new position. GameBase* pObj = (GameBase*) g_pLTServer->HandleToObject(theStruct.hObj); if (!pObj) return; HOBJECT hMoveObj = LTNULL; HOBJECT hFarObj = LTNULL; ObjectList* pMarkList = pObj->GetMarkList(); if (pMarkList) { uint8 nNumMarks = pMarkList->m_nInList; ObjectLink* pLink = pMarkList->m_pFirstLink; LTFLOAT fClosestMarkDist = REGION_DIAMETER; LTFLOAT fFarthestMarkDist = 0.0f; uint8 nNumInRegion = 0; LTVector vPos; for (int i=0; i < nNumMarks && pLink; i++) { if (pLink->m_hObject) { HATTACHMENT hAttachment; if (LT_OK == g_pLTServer->FindAttachment(theStruct.hObj, pLink->m_hObject, &hAttachment)) { LTransform transform; g_pLTServer->Common()->GetAttachmentTransform(hAttachment, transform, LTTRUE); vPos = transform.m_Pos; } LTFLOAT fDist = VEC_DISTSQR(vPos, theStruct.vPos); if (fDist < REGION_DIAMETER) { if (fDist < fClosestMarkDist) { fClosestMarkDist = fDist; hMoveObj = pLink->m_hObject; } if (++nNumInRegion > MAX_MARKS_IN_REGION) { // Just move this mark to the correct pos... hMoveObj = hMoveObj ? hMoveObj : pLink->m_hObject; break; } } if (fDist > fFarthestMarkDist) { fFarthestMarkDist = fDist; hFarObj = pLink->m_hObject; } } pLink = pLink->m_pNext; } // If we've got the max number of marks on this object, just move // the closest one to the new position... if (nNumMarks >= MAX_MARKS_PER_OBJECT) { hMoveObj = hMoveObj ? hMoveObj : (hFarObj ? hFarObj : pMarkList->m_pFirstLink->m_hObject); } else { hMoveObj = LTNULL; // Need to create one... } } // Re-setup the object to move it... if (hMoveObj && IsKindOf(hMoveObj, "CServerMark")) { CServerMark* pMoveMark = (CServerMark*) g_pLTServer->HandleToObject(hMoveObj); if (!pMoveMark) return; // Since this mark is already attached to pObj, remove the attachment // (since CServerMark::Setup() will re-attach it)... HATTACHMENT hAttachment; if (LT_OK == g_pLTServer->FindAttachment(theStruct.hObj, hMoveObj, &hAttachment)) { g_pLTServer->RemoveAttachment(hAttachment); } pMoveMark->Setup((CLIENTWEAPONFX)theStruct); return; } // Okay, no luck, need to create a new mark... ObjectCreateStruct createStruct; INIT_OBJECTCREATESTRUCT(createStruct); LTFLOAT fScaleAdjust = 1.0f; if (!GetImpactSprite((SurfaceType)theStruct.nSurfaceType, fScaleAdjust, theStruct.nAmmoId, createStruct.m_Filename, ARRAY_LEN(createStruct.m_Filename))) { return; } createStruct.m_ObjectType = OT_SPRITE; createStruct.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATEABLESPRITE; createStruct.m_Pos = theStruct.vPos; g_pLTServer->AlignRotation(&(createStruct.m_Rotation), &((LTVector)theStruct.vSurfaceNormal), LTNULL); HCLASS hClass = g_pLTServer->GetClass("CServerMark"); CServerMark* pMark = (CServerMark*) g_pLTServer->CreateObject(hClass, &createStruct); if (!pMark) return; // Add the mark to the object... pObj->AddMark(pMark->m_hObject); // Randomly adjust the mark's scale to add a bit o spice... if (pAmmo->pImpactFX) { LTFLOAT fScale = fScaleAdjust * pAmmo->pImpactFX->fMarkScale; LTVector vScale; VEC_SET(vScale, fScale, fScale, fScale); g_pLTServer->ScaleObject(pMark->m_hObject, &vScale); } pMark->Setup((CLIENTWEAPONFX)theStruct); }
void ForestWindMgr::processTick() { const F32 timeDelta = 0.032f; if ( mEmitters.empty() ) return; PROFILE_SCOPE(ForestWindMgr_AdvanceTime); // Advance all ForestWinds. { PROFILE_SCOPE(ForestWindMgr_AdvanceTime_ForestWind_ProcessTick); ForestWindEmitterList::iterator iter = mEmitters.begin(); for ( ; iter != mEmitters.end(); iter++ ) { if ( (*iter)->getWind() && (*iter)->isEnabled() ) { (*iter)->updateMountPosition(); ForestWind *wind = (*iter)->getWind(); if ( wind ) wind->processTick(); } } } // Assign the new global wind value used by the particle system. { ForestWindEmitter *pWindEmitter = getGlobalWind(); if ( pWindEmitter == NULL ) ParticleEmitter::setWindVelocity( Point3F::Zero ); else { ForestWind *pWind = pWindEmitter->getWind(); ParticleEmitter::setWindVelocity( pWind->getDirection() * pWind->getStrength() ); } } // Get the game connection and camera object // in order to retrieve the camera position. GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; GameBase *cam = conn->getCameraObject(); if ( !cam ) return; const Point3F &camPos = cam->getPosition(); // Gather TreePlacementInfo for trees near the camera. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_GatherTreePlacementInfo ); smAdvanceSignal.trigger( camPos, smWindEffectRadius, &mPlacementInfo ); } // Prepare to build a new local source map. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_SwapSources ); AssertFatal( mPrevSources->isEmpty(), "prev sources not empty!" ); swap( mSources, mPrevSources ); AssertFatal( mSources->isEmpty(), "swap failed!" ); } // Update wind for each TreePlacementInfo { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_UpdateWind ); for( S32 i = 0; i < mPlacementInfo.size(); i++ ) { const TreePlacementInfo &info = mPlacementInfo[i]; updateWind( camPos, info, timeDelta ); } mPlacementInfo.clear(); } // Clean up any accumulators in the // previous local source map. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_Cleanup ); IdToWindMap::Iterator sourceIter = mPrevSources->begin(); for( ; sourceIter != mPrevSources->end(); sourceIter++ ) { ForestWindAccumulator *accum = (*sourceIter).value; AssertFatal( accum, "Got null accumulator!" ); delete accum; } mPrevSources->clear(); } }
void MainMenuState::init(GameBase &game) { _game = &game; _game->getEngine()->getDrawEngine()->loadText("maintitle", "Main menu", { 255, 255, 255 }, "trebucbd", 48); //std::function<void(MenuItem *item)> callBack = &MainMenuState::menuAction; _menu = new Menu(50, 250, game); _menu->addMenuTextItem("Play", (std::function<void()>)[&] { changeState(*_game, GameModeState::getInstance()); }); _menu->addMenuTextItem("Level editor", (std::function<void()>)[&] { _game->setGameMode(GameBase::GameMode::Edit); _game->getStateManager()->changeState(LevelSelectionState::getInstance()); }); _menu->addMenuTextItem("Options", (std::function<void()>)[&] { _game->getStateManager()->pushState(OptionsState::getInstance()); }); _menu->addMenuTextItem("Credits", (std::function<void()>)[&] { _game->getStateManager()->pushState(CreditsState::getInstance()); }); auto files = util::FileManager::getInstance().getFiles("assets\\playbacks\\"); auto file = std::find(files.begin(), files.end(), "recording"); if (file != files.end()) { _menu->addMenuTextItem("Playback", (std::function<void()>)[&] { _game->setGameMode(GameBase::GameMode::Playback); LoadingPlayBackState::getInstance().setPlaybackFileName("recording"); _game->getStateManager()->changeState(LoadingPlayBackState::getInstance()); }); } _menu->addMenuTextItem("Quit", (std::function<void()>)[&] { _game->stop(); }); game.getEngine()->getAudioEngine()->load("main_menu_bgm", "assets/sounds/mainmenu/bgm.mp3", AUDIOTYPE::MUSIC); //game.getEngine()->getAudioEngine()->load("menu_switch_effect", R"(assets/sounds/effects/menu_sound3.ogg)", AUDIOTYPE::SOUND_EFFECT); game.getEngine()->getAudioEngine()->play("main_menu_bgm", 0); game.getEngine()->getInputEngine()->setMouseEnabled(); game.getEngine()->getDrawEngine()->load("mainmenu_background", "assets/screens/mainmenu"); //game.getEngine()->getDrawEngine()->load("menu_play", "assets/screens/main/play"); //game.getEngine()->getDrawEngine()->load("menu_options", "assets/screens/main/options"); //game.getEngine()->getDrawEngine()->load("menu_credits", "assets/screens/mainm/credits"); //game.getEngine()->getDrawEngine()->load("menu_quit", "assets/screens/main/quit"); _advertisementIndex = -1; _advertisementRefreshRate = 15 * 10000; _lastTimeSinceAdvertisementChange = 0; if (_advertismentList != nullptr) { delete _advertismentList; _advertismentList = nullptr; } _advertismentList = new std::vector<std::string>(util::FileManager::getInstance().getFiles("assets/advertisements/")); if (_advertismentList->size() > 0) { loadAdvertisement(); _shouldRefreshAdvertisement = _advertismentList->size() > 1; } // Load game if (ProgressManager::getInstance().currentSavegame < 0) _game->getStateManager()->pushState(ProgressLoadState::getInstance()); }
void CreateLevelState::cleanup(GameBase &game) { delete _name; delete _error; game.getEngine()->getDrawEngine()->unloadAll(); }
void HifiClientProcessList::clientCatchup(GameConnection * connection) { #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client catching up... (%i)%s", mCatchup, mForceHifiReset ? " reset" : ""); #endif if (connection->getControlObject() && connection->getControlObject()->isGhostUpdated()) // if control object is reset, make sure moves are reset too connection->mMoveList->resetCatchup(); const F32 maxVel = mSqrt(gMaxHiFiVelSq) * 1.25f; F32 dt = F32(mCatchup+1) * TickSec; Point3F bigDelta(maxVel*dt,maxVel*dt,maxVel*dt); // walk through all process objects looking for ones which were updated // -- during first pass merely collect neighbors which need to be reset and updated in unison ProcessObject * pobj; if (mCatchup && !mForceHifiReset) { for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); static SimpleQueryList nearby; nearby.mList.clear(); // check for nearby objects which need to be reset and then caught up // note the funky loop logic -- first time through obj is us, then // we start iterating through nearby list (to look for objects nearby // the nearby objects), which is why index starts at -1 // [objects nearby the nearby objects also get added to the nearby list] for (S32 i=-1; obj; obj = ++i<nearby.mList.size() ? (GameBase*)nearby.mList[i] : NULL) { if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType) && !obj->isNetNearbyAdded()) { Point3F start = obj->getWorldSphere().center; Point3F end = start + 1.1f * dt * obj->getVelocity(); F32 rad = 1.5f * obj->getWorldSphere().radius; // find nearby items not updated but are hi fi, mark them as updated (and restore old loc) // check to see if added items have neighbors that need updating Box3F box; Point3F rads(rad,rad,rad); box.minExtents = box.maxExtents = start; box.minExtents -= bigDelta + rads; box.maxExtents += bigDelta + rads; // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // add marble blast hack so hifi networking can see hidden objects // (since hidden is under control of hifi networking) // gForceNotHidden = true; S32 j = nearby.mList.size(); gClientContainer.findObjects(box, GameBaseHiFiObjectType, SimpleQueryList::insertionCallback, &nearby); // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // disable above hack // gForceNotHidden = false; // drop anyone not heading toward us or already checked for (; j<nearby.mList.size(); j++) { GameBase * obj2 = (GameBase*)nearby.mList[j]; // if both passive, these guys don't interact with each other bool passive = obj->isHifiPassive() && obj2->isHifiPassive(); if (!obj2->isGhostUpdated() && !passive) { // compare swept spheres of obj and obj2 // if collide, reset obj2, setGhostUpdated(true), and continue Point3F end2 = obj2->getWorldSphere().center; Point3F start2 = end2 - 1.1f * dt * obj2->getVelocity(); F32 rad2 = 1.5f * obj->getWorldSphere().radius; if (MathUtils::capsuleCapsuleOverlap(start,end,rad,start2,end2,rad2)) { // better add obj2 obj2->getTickCache().beginCacheList(); TickCacheEntry * tce = obj2->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj2->readPacketData(connection,&bs); obj2->setGhostUpdated(true); // continue so we later add the neighbors too continue; } } // didn't pass above test...so don't add it or nearby objects nearby.mList[j] = nearby.mList.last(); nearby.mList.decrement(); j--; } obj->setNetNearbyAdded(true); } } } } // save water mark -- for game base list FrameAllocatorMarker mark; // build ordered list of client objects which need to be caught up GameBaseListNode list; for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); //GameBase *obj = dynamic_cast<GameBase*>( pobj ); //GameBase *obj = (GameBase*)pobj; // Not a GameBase object so nothing to do. if ( !obj ) continue; if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); // begin iterating through tick list (skip first tick since that is the state we've been reset to) obj->getTickCache().beginCacheList(); obj->getTickCache().incCacheList(); } else if (mForceHifiReset && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // add all hifi objects obj->getTickCache().beginCacheList(); TickCacheEntry * tce = obj->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->readPacketData(connection,&bs); obj->setGhostUpdated(true); // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj == connection->getControlObject() && obj->isGhostUpdated()) { // construct process object and add it to the list // hold pointer to our object in mAfterObject // .. but this is not a hi fi object, so don't mess with tick cache GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj->isGhostUpdated()) { // not hifi but we were updated, so perform net smooth now obj->computeNetSmooth(mLastDelta); } // clear out work flags obj->setNetNearbyAdded(false); obj->setGhostUpdated(false); } // run through all the moves in the move list so we can play them with our control object Move* movePtr; U32 numMoves; connection->mMoveList->resetClientMoves(); connection->mMoveList->getMoves(&movePtr, &numMoves); AssertFatal(mCatchup<=numMoves,"doh"); // tick catchup time for (U32 m=0; m<mCatchup; m++) { for (GameBaseListNode * walk = list.mNext; walk != &list; walk = walk->mNext) { // note that we get object from after object not getGameBase function // this is because we are an on the fly linked list which uses mAfterObject // rather than the linked list embedded in GameBase (clean this up?) GameBase * obj = walk->mObject; // it's possible for a non-hifi object to get in here, but // only if it is a control object...make sure we don't do any // of the tick cache stuff if we are not hifi. bool hifi = obj->getTypeMask() & GameBaseHiFiObjectType; TickCacheEntry * tce = hifi ? obj->getTickCache().incCacheList() : NULL; // tick object if (obj==connection->getControlObject()) { obj->processTick(movePtr); movePtr->checksum = obj->getPacketDataChecksum(connection); movePtr++; } else { AssertFatal(tce && hifi,"Should not get in here unless a hi fi object!!!"); obj->processTick(tce->move); } if (hifi) { BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->writePacketData(connection,&bs); } } if (connection->getControlObject() == NULL) movePtr++; } connection->mMoveList->clearMoves(mCatchup); // Handle network error smoothing here...but only for control object GameBase * control = connection->getControlObject(); if (control && !control->isNewGhost()) { control->computeNetSmooth(mLastDelta); control->setNewGhost(false); } if (moveSync.doAction() && moveSync.moveDiff>0) { S32 moveDiff = moveSync.moveDiff; #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client timewarping to catchup %i moves",moveDiff); #endif while (moveDiff--) advanceObjects(); moveSync.reset(); } #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("---------"); #endif // all caught up mCatchup = 0; }