Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Jul 3, 2011, 5:42:19 PM (13 years ago)
Author:
dafrick
Message:

Cleaning up in SpaceShip and Engine. Fixed several bugs.
Kicked localLinearAcceleration, primaryThrust and auxiliaryThrust out of the SpaceShip, since it wasn't used anymore.
Moved the trail lights back a bit.
Added some documentation to SpaceShip and Engine.
SpeedPickup is working again, will need some further tuning.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/trunk/src/orxonox/worldentities/pawns/SpaceShip.cc

    r8706 r8727  
    3636#include "core/XMLPort.h"
    3737#include "tools/Shader.h"
    38 #include "util/Debug.h" // TODO: Needed?
    3938#include "util/Math.h"
    4039
     
    4746namespace orxonox
    4847{
    49     const float orientationGain = 100;
    5048    CreateFactory(SpaceShip);
    5149
     
    5452        RegisterObject(SpaceShip);
    5553
    56         this->primaryThrust_  = 100;
    57         this->auxilaryThrust_ =  30;
     54        this->bInvertYAxis_ = false;
     55
     56        this->steering_ = Vector3::ZERO;
     57
    5858        this->rotationThrust_ =  10;
    59 
    60         this->localLinearAcceleration_.setValue(0, 0, 0);
    6159        this->localAngularAcceleration_.setValue(0, 0, 0);
     60
    6261        this->bBoost_ = false;
    63         this->steering_ = Vector3::ZERO;
    64 
     62        this->bBoostCooldown_ = false;
     63        this->initialBoostPower_ = 10.0f;
    6564        this->boostPower_ = 10.0f;
    66         this->initialBoostPower_ = 10.0f;
    67         this->boostRate_ = 5.0;
    68         this->boostPowerRate_ = 1.0;
    69         this->boostCooldownDuration_ = 5.0;
    70         this->bBoostCooldown_ = false;
    71 
    72         this->lift_ = 1.0f;                         // factor of the lift, standard is 1
    73         this->stallSpeed_ = 220.0f;                 // max speed where lift is added
    74 
    75         this->bInvertYAxis_ = false;
     65        this->boostPowerRate_ = 1.0f;
     66        this->boostRate_ = 5.0f;
     67        this->boostCooldownDuration_ = 5.0f;
     68
     69        this->shakeFrequency_ = 15.0f;
     70        this->shakeAmplitude_ = 5.0f;
     71        this->shakeDt_ = 0.0f;
     72        this->cameraOriginalPosition_ = Vector3::UNIT_SCALE;
     73        this->cameraOriginalOrientation_ = Quaternion::IDENTITY;
     74
     75        this->lift_ = 1.0f;
     76        this->stallSpeed_ = 220.0f;
    7677
    7778        this->setDestroyWhenPlayerLeft(true);
     
    8384        this->enableCollisionCallback();
    8485
    85         this->engineTicksNotDone = 0;
    8686        this->setConfigValues();
    8787        this->registerVariables();
    88        
    89         this->cameraOriginalPosition_ = Vector3::UNIT_SCALE;
    90         this->cameraOriginalOrientation_ = Quaternion::IDENTITY;
    91 
    92         this->shakeFrequency_ = 15;
    93         this->shakeAmplitude_ = 5;
    94         this->shakeDt_ = 0;
     88
    9589    }
    9690
     
    10094        {
    10195            this->removeAllEngines();
    102        
     96
    10397            if (this->boostBlur_)
    10498                this->boostBlur_->destroy();
     
    110104        SUPER(SpaceShip, XMLPort, xmlelement, mode);
    111105
    112         //XMLPortParam(SpaceShip, "engine",            setEngineTemplate,    getEngineTemplate,    xmlelement, mode);
    113         XMLPortParamVariable(SpaceShip, "primaryThrust",  primaryThrust_,  xmlelement, mode);
    114         XMLPortParamVariable(SpaceShip, "auxilaryThrust", auxilaryThrust_, xmlelement, mode);
    115106        XMLPortParamVariable(SpaceShip, "rotationThrust", rotationThrust_, xmlelement, mode);
    116         XMLPortParamVariable(SpaceShip, "boostPower", initialBoostPower_, xmlelement, mode);
    117         XMLPortParamVariable(SpaceShip, "boostPowerRate", boostPowerRate_, xmlelement, mode);
    118         XMLPortParamVariable(SpaceShip, "boostRate", boostRate_, xmlelement, mode);
    119         XMLPortParamVariable(SpaceShip, "boostCooldownDuration", boostCooldownDuration_, xmlelement, mode);
    120         XMLPortParamVariable(SpaceShip, "shakeFrequency", shakeFrequency_, xmlelement, mode);
    121         XMLPortParamVariable(SpaceShip, "shakeAmplitude", shakeAmplitude_, xmlelement, mode);
     107        XMLPortParam(SpaceShip, "boostPower", setInitialBoostPower, getInitialBoostPower, xmlelement, mode);
     108        XMLPortParam(SpaceShip, "boostPowerRate", setBoostPowerRate, getBoostPowerRate, xmlelement, mode);
     109        XMLPortParam(SpaceShip, "boostRate", setBoostRate, getBoostRate, xmlelement, mode);
     110        XMLPortParam(SpaceShip, "boostCooldownDuration", setBoostCooldownDuration, getBoostCooldownDuration, xmlelement, mode);
     111        XMLPortParam(SpaceShip, "shakeFrequency", setShakeFrequency, getShakeFrequency, xmlelement, mode);
     112        XMLPortParam(SpaceShip, "shakeAmplitude", setShakeAmplitude, getShakeAmplitude, xmlelement, mode);
    122113        XMLPortParamVariable(SpaceShip, "lift", lift_, xmlelement, mode);
    123114        XMLPortParamVariable(SpaceShip, "stallSpeed", stallSpeed_, xmlelement, mode);
     
    128119    void SpaceShip::registerVariables()
    129120    {
    130         registerVariable(this->primaryThrust_,  VariableDirection::ToClient);
    131         registerVariable(this->auxilaryThrust_, VariableDirection::ToClient);
    132121        registerVariable(this->rotationThrust_, VariableDirection::ToClient);
    133         // TODO: Synchronization of boost needed?
    134122        registerVariable(this->boostPower_, VariableDirection::ToClient);
    135123        registerVariable(this->boostPowerRate_, VariableDirection::ToClient);
     
    169157        SUPER(SpaceShip, tick, dt);
    170158
     159        // Run the engines
     160        for(std::vector<Engine*>::iterator it = this->engineList_.begin(); it != this->engineList_.end(); it++)
     161            (*it)->run(dt);
     162
    171163        if (this->hasLocalController())
    172164        {
    173             // Handle mouse look
     165            // If not in mouse look apply the angular movement to the ship.
    174166            if (!this->isInMouseLook())
    175167            {
     
    179171            this->localAngularAcceleration_.setValue(0, 0, 0);
    180172
    181             // Charge boostPower
    182             if(!this->bBoostCooldown_ && this->boostPower_ < this->initialBoostPower_)
     173            // If not in boost cooldown, the boost power is recharged up to the initial boost power.
     174            if(!this->isBoostCoolingDown() && this->boostPower_ < this->initialBoostPower_)
    183175            {
    184176                this->boostPower_ += this->boostPowerRate_*dt;
    185177            }
    186             // Use boostPower
    187             if(this->bBoost_)
     178            // If boosting
     179            if(this->isBoosting())
    188180            {
    189                 this->boostPower_ -=this->boostRate_*dt;
     181                // Discount the used power
     182                this->boostPower_ -= this->boostRate_*dt;
     183                // If the power has been used up boosting is stopped and boost cooldown is initiated.
    190184                if(this->boostPower_ <= 0.0f)
    191185                {
     
    195189                }
    196190
     191                // Shake the camera because of the boosting.
    197192                this->shakeCamera(dt);
    198193            }
    199194
    200195            // Enable Blur depending on settings
    201             if (this->bEnableMotionBlur_ && !this->boostBlur_ && this->hasLocalController() && this->hasHumanController())
     196            if(this->bEnableMotionBlur_)
    202197            {
    203                 this->boostBlur_ = new Shader(this->getScene()->getSceneManager());
    204                 this->boostBlur_->setCompositorName("Radial Blur");
     198                if (this->boostBlur_ == NULL && this->hasLocalController() && this->hasHumanController())
     199                {
     200                    this->boostBlur_ = new Shader(this->getScene()->getSceneManager());
     201                    this->boostBlur_->setCompositorName("Radial Blur");
     202                }
     203                if (this->boostBlur_)
     204                {
     205                    float blur = this->blurStrength_ * clamp(-this->getLocalVelocity().z/(this->getMaxSpeedFront()*this->getBoostFactor()), 0.0f, 1.0f);
     206
     207                    // Show and hide blur effect depending on state of booster
     208                    if(this->isBoosting())
     209                        this->boostBlur_->setVisible(blur > 0.0f);
     210                    else
     211                        this->boostBlur_->setVisible(false);
     212
     213                    this->boostBlur_->setParameter(0, 0, "sampleStrength", blur);
     214                }
    205215            }
    206 
    207             if (this->boostBlur_) // && this->maxSpeedFront_ != 0 && this->boostFactor_ != 1)
    208             {
    209                 // TODO: this->maxSpeedFront_ gets fastest engine
    210                 float blur = this->blurStrength_ * clamp((-this->getLocalVelocity().z - 0.0f /*this->maxSpeedFront_*/) / ((150.0f /*boostFactor_*/ - 1) * 1.5f /*this->maxSpeedFront_*/), 0.0f, 1.0f);
    211 
    212                 // Show and hide blur effect depending on state of booster
    213                 if(this->bBoost_)
    214                     this->boostBlur_->setVisible(blur > 0);
    215                 else
    216                     this->boostBlur_->setVisible(false);
    217 
    218                 this->boostBlur_->setParameter(0, 0, "sampleStrength", blur);
    219             }
    220         }
    221     }
    222 
    223     void SpaceShip::moveFrontBack(const Vector2& value)
    224     {
    225         this->localLinearAcceleration_.setZ(this->localLinearAcceleration_.z() - value.x);
    226         this->steering_.z -= value.x;
    227     }
    228 
    229     void SpaceShip::moveRightLeft(const Vector2& value)
    230     {
    231         this->localLinearAcceleration_.setX(this->localLinearAcceleration_.x() + value.x);
    232         this->steering_.x += value.x;
    233     }
    234 
    235     void SpaceShip::moveUpDown(const Vector2& value)
    236     {
    237         this->localLinearAcceleration_.setY(this->localLinearAcceleration_.y() + value.x);
    238         this->steering_.y += value.x;
    239     }
    240 
     216        }
     217
     218        this->steering_ = Vector3::ZERO;
     219    }
     220
     221    /**
     222    @brief
     223        Rotate in yaw direction.
     224        Due to added lift, can also lead to an additional right-left motion.
     225    @param value
     226        A vector whose first component specifies the magnitude of the rotation. Positive means yaw left, negative means yaw right.
     227    */
    241228    void SpaceShip::rotateYaw(const Vector2& value)
    242229    {
     
    245232        Pawn::rotateYaw(value);
    246233
    247         //This function call adds a lift to the ship when it is rotating to make it's movement more "realistic" and enhance the feeling.
    248         if (abs(this-> getLocalVelocity().z) < stallSpeed_)  {this->moveRightLeft(-lift_ / 5 * value * sqrt(abs(this-> getLocalVelocity().z)));}
    249     }
    250 
     234        // This function call adds a lift to the ship when it is rotating to make it's movement more "realistic" and enhance the feeling.
     235        if (this->getLocalVelocity().z < 0 && abs(this->getLocalVelocity().z) < stallSpeed_)
     236            this->moveRightLeft(-lift_ / 5.0f * value * sqrt(abs(this->getLocalVelocity().z)));
     237    }
     238
     239    /**
     240    @brief
     241        Rotate in pitch direction.
     242        Due to added left, can also lead to an additional up-down motion.
     243    @param value
     244        A vector whose first component specifies the magnitude of the rotation. Positive means pitch up, negative means pitch down.
     245    */
    251246    void SpaceShip::rotatePitch(const Vector2& value)
    252247    {
    253         this->localAngularAcceleration_.setX(this->localAngularAcceleration_.x() + value.x*0.8f);
    254 
    255         Pawn::rotatePitch(value);
    256 
    257         //This function call adds a lift to the ship when it is pitching to make it's movement more "realistic" and enhance the feeling.
    258         if (abs(this-> getLocalVelocity().z) < stallSpeed_)  {this->moveUpDown(lift_ / 5 * value * sqrt(abs(this-> getLocalVelocity().z)));}
    259     }
    260 
     248        Vector2 pitch = value;
     249        if(this->bInvertYAxis_)
     250            pitch.x = -pitch.x;
     251
     252        this->localAngularAcceleration_.setX(this->localAngularAcceleration_.x() + pitch.x*0.8f);
     253
     254        Pawn::rotatePitch(pitch);
     255
     256        // This function call adds a lift to the ship when it is pitching to make it's movement more "realistic" and enhance the feeling.
     257        if (this->getLocalVelocity().z < 0 && abs(this->getLocalVelocity().z) < stallSpeed_)
     258            this->moveUpDown(lift_ / 5.0f * pitch * sqrt(abs(this->getLocalVelocity().z)));
     259    }
     260
     261    /**
     262    @brief
     263        Rotate in roll direction.
     264    @param value
     265        A vector whose first component specifies the magnitude of the rotation. Positive means roll left, negative means roll right.
     266    */
    261267    void SpaceShip::rotateRoll(const Vector2& value)
    262268    {
     
    278284    void SpaceShip::boost(bool bBoost)
    279285    {
    280         if(bBoost && !this->bBoostCooldown_)
     286        // Can only boost if not cooling down.
     287        if(bBoost && !this->isBoostCoolingDown())
    281288        {
    282289            this->bBoost_ = true;
    283             Camera* camera = CameraManager::getInstance().getActiveCamera();
    284             this->cameraOriginalPosition_ = camera->getPosition();
    285             this->cameraOriginalOrientation_ = camera->getOrientation();
    286         }
     290            this->backupCamera();
     291        }
     292        // Stop boosting.
    287293        if(!bBoost)
    288294        {
     
    292298    }
    293299
    294     void SpaceShip::boostCooledDown(void)
    295     {
    296         this->bBoostCooldown_ = false;
    297     }
    298    
    299     void SpaceShip::shakeCamera(float dt)
    300     {
    301         //make sure the ship is only shaking if it's moving
    302         if (this->getVelocity().squaredLength() > 80.0f)
    303         {
    304             this->shakeDt_ += dt;
    305    
    306             float frequency = this->shakeFrequency_ * (this->getVelocity().squaredLength());
    307    
    308             if (this->shakeDt_ >= 1.0f/frequency)
    309             {
    310                 this->shakeDt_ -= 1.0f/frequency;
    311             }
    312    
    313             Degree angle = Degree(sin(this->shakeDt_ *2.0f* math::pi * frequency) * this->shakeAmplitude_);
    314    
    315             //COUT(0) << "Angle: " << angle << std::endl;
    316             Camera* camera = this->getCamera();
    317 
    318             //Shaking Camera effect
    319             if (camera != 0)
    320             {
    321                 camera->setOrientation(Vector3::UNIT_X, angle);
    322             }
    323         }
    324     }
    325 
    326     void SpaceShip::resetCamera()
    327     {
    328         Camera *camera = this->getCamera();
    329 
    330         if (camera == 0)
    331         {
    332             COUT(2) << "Failed to reset camera!";
    333             return;
    334         }
    335    
    336         this->shakeDt_ = 0;
    337         camera->setPosition(this->cameraOriginalPosition_);
    338         camera->setOrientation(this->cameraOriginalOrientation_);
    339     }
    340 
    341     void SpaceShip::backupCamera()
    342     {
    343         Camera* camera = CameraManager::getInstance().getActiveCamera();
    344         if(camera != NULL)
    345         {
    346             this->cameraOriginalPosition_ = camera->getPosition();
    347             this->cameraOriginalOrientation_ = camera->getOrientation();
    348         }
    349     }
    350 
     300        /**
     301    @brief
     302        Add an Engine to the SpaceShip.
     303    @param engine
     304        A pointer to the Engine to be added.
     305    */
    351306    void SpaceShip::addEngine(orxonox::Engine* engine)
    352307    {
    353         //COUT(0)<<"Adding an Engine: " << engine << endl;
     308        OrxAssert(engine != NULL, "The engine cannot be NULL.");
    354309        this->engineList_.push_back(engine);
    355310        engine->addToSpaceShip(this);
    356         this->resetEngineTicks();
    357     }
    358 
    359     bool SpaceShip::hasEngine(Engine* engine)
    360     {
    361         for(unsigned int i=0; i<this->engineList_.size(); i++)
    362         {
    363             if(this->engineList_[i]==engine)
     311    }
     312
     313    /**
     314    @brief
     315        Check whether the SpaceShip has a particular Engine.
     316    @param engine
     317        A pointer to the Engine to be checked.
     318    */
     319    bool SpaceShip::hasEngine(Engine* engine) const
     320    {
     321        for(unsigned int i = 0; i < this->engineList_.size(); i++)
     322        {
     323            if(this->engineList_[i] == engine)
    364324                return true;
    365325        }
     
    367327    }
    368328
     329    /**
     330    @brief
     331        Get the i-th Engine of the SpaceShip.
     332    @return
     333        Returns a pointer to the i-the Engine. NULL if there is no Engine with that index.
     334    */
    369335    Engine* SpaceShip::getEngine(unsigned int i)
    370336    {
    371         if(this->engineList_.size()>=i)
    372             return 0;
     337        if(this->engineList_.size() >= i)
     338            return NULL;
    373339        else
    374340            return this->engineList_[i];
    375341    }
    376342
     343    /**
     344    @brief
     345        Remove and destroy all Engines of the SpaceShip.
     346    */
    377347    void SpaceShip::removeAllEngines()
    378348    {
     
    380350            this->engineList_.back()->destroy();
    381351    }
    382    
     352
     353    /**
     354    @brief
     355        Remove a particular Engine from the SpaceShip.
     356    @param engine
     357        A pointer to the Engine to be removed.
     358    */
    383359    void SpaceShip::removeEngine(Engine* engine)
    384360    {
    385         for(std::vector<Engine*>::iterator it=this->engineList_.begin(); it!=this->engineList_.end(); ++it)
    386         {
    387             if(*it==engine)
     361        for(std::vector<Engine*>::iterator it = this->engineList_.begin(); it != this->engineList_.end(); ++it)
     362        {
     363            if(*it == engine)
    388364            {
    389365                this->engineList_.erase(it);
     
    393369    }
    394370
    395     void SpaceShip::setSpeedFactor(float factor)
     371    /**
     372    @brief
     373        Add to the speed factor for all engines of the SpaceShip.
     374    @param factor
     375        The factor to be added.
     376    */
     377    void SpaceShip::addSpeedFactor(float factor)
    396378    {
    397379        for(unsigned int i=0; i<this->engineList_.size(); i++)
    398             this->engineList_[i]->setSpeedFactor(factor);
    399     }
    400     float SpaceShip::getSpeedFactor() // Calculate mean SpeedFactor.
    401     {
    402         float ret = 0; unsigned int i = 0;
     380            this->engineList_[i]->addSpeedMultiply(factor);
     381    }
     382
     383    /**
     384    @brief
     385        Add to the speed factor for all engines of the SpaceShip.
     386    @param speed
     387        The speed to be added.
     388    */
     389    void SpaceShip::addSpeed(float speed)
     390    {
     391        for(unsigned int i=0; i<this->engineList_.size(); i++)
     392            this->engineList_[i]->addSpeedAdd(speed);
     393    }
     394
     395    /**
     396    @brief
     397        Get the mean speed factor over all engines of the SpaceShip.
     398    @return
     399        Returns the mean speed factor over all engines of the SpaceShip.
     400    */
     401    float SpaceShip::getSpeedFactor() const
     402    {
     403        float sum = 0;
     404        unsigned int i = 0;
    403405        for(; i<this->engineList_.size(); i++)
    404             ret += this->engineList_[i]->getSpeedFactor();
    405         ret /= (float)i;
    406         return ret;
    407     }
    408     float SpaceShip::getMaxSpeedFront()
    409     {
    410         float ret=0;
     406            sum += this->engineList_[i]->getSpeedMultiply();
     407        return sum/float(i);
     408    }
     409
     410    /**
     411    @brief
     412        Get the largest maximal forward speed over all engines of the SpaceShip.
     413    @return
     414        Returns the largest forward speed over all engines of the SpaceShip.
     415    */
     416    float SpaceShip::getMaxSpeedFront() const
     417    {
     418        float speed=0;
    411419        for(unsigned int i=0; i<this->engineList_.size(); i++)
    412420        {
    413             if(this->engineList_[i]->getMaxSpeedFront() > ret)
    414                 ret = this->engineList_[i]->getMaxSpeedFront();
    415         }
    416         return ret;
    417     }
    418 
    419     float SpaceShip::getBoostFactor()
    420     {
    421         float ret = 0; unsigned int i=0;
     421            if(this->engineList_[i]->getMaxSpeedFront() > speed)
     422                speed = this->engineList_[i]->getMaxSpeedFront();
     423        }
     424        return speed;
     425    }
     426
     427    /**
     428    @brief
     429        Get the mean boost factor over all engines of the SpaceShip.
     430    @return
     431        Returns the mean boost factor over all engines of the SpaceShip.
     432    */
     433    float SpaceShip::getBoostFactor() const
     434    {
     435        float sum = 0;
     436        unsigned int i=0;
    422437        for(; i<this->engineList_.size(); i++)
    423             ret += this->engineList_[i]->getBoostFactor();
    424         ret /= (float)i;
    425         return ret;
    426     }
    427 
    428     std::vector<PickupCarrier*>* SpaceShip::getCarrierChildren(void) const
    429     {
    430         std::vector<PickupCarrier*>* list = new std::vector<PickupCarrier*>();
    431         for(unsigned int i=0; i<this->engineList_.size(); i++)
    432             list->push_back(this->engineList_[i]);
    433         return list;
    434     }
    435    
     438            sum += this->engineList_[i]->getBoostFactor();
     439        return sum/float(i);
     440    }
     441
     442    /**
     443    @brief
     444        Is called when the enableMotionBlur config value has changed.
     445    */
    436446    void SpaceShip::changedEnableMotionBlur()
    437447    {
    438         if (!this->bEnableMotionBlur_)
     448        if (!this->bEnableMotionBlur_ && this->boostBlur_ != NULL)
    439449        {
    440450            this->boostBlur_->destroy();
    441             this->boostBlur_ = 0;
    442         }
     451            this->boostBlur_ = NULL;
     452        }
     453    }
     454
     455    /**
     456    @brief
     457        Shake the camera for a given time interval.
     458    @param dt
     459        The time interval in seconds.
     460    */
     461    void SpaceShip::shakeCamera(float dt)
     462    {
     463        // Make sure the ship is only shaking if it's moving forward and above the maximal forward speed.
     464        if (-this->getLocalVelocity().z > this->getMaxSpeedFront())
     465        {
     466            this->shakeDt_ += dt;
     467
     468            float frequency = this->shakeFrequency_ * (square(abs(this->getLocalVelocity().z)));
     469
     470            if (this->shakeDt_ >= 1.0f/frequency)
     471                this->shakeDt_ -= 1.0f/frequency;
     472
     473            Degree angle = Degree(sin(this->shakeDt_ * math::twoPi * frequency) * this->shakeAmplitude_);
     474
     475            Camera* camera = this->getCamera();
     476            //Shaking Camera effect
     477            if (camera != 0)
     478                camera->setOrientation(Vector3::UNIT_X, angle);
     479
     480        }
     481        // If the camera is no shaking, reset it.
     482        else
     483            this->resetCamera();
     484    }
     485
     486    /**
     487    @brief
     488        Save the original position and orientation of the camera.
     489    */
     490    void SpaceShip::backupCamera()
     491    {
     492        Camera* camera = CameraManager::getInstance().getActiveCamera();
     493        if(camera != NULL)
     494        {
     495            this->cameraOriginalPosition_ = camera->getPosition();
     496            this->cameraOriginalOrientation_ = camera->getOrientation();
     497        }
     498    }
     499
     500    /**
     501    @brief
     502        Reset the camera to its original position.
     503    */
     504    void SpaceShip::resetCamera()
     505    {
     506        Camera *camera = this->getCamera();
     507        if (camera == 0)
     508        {
     509            COUT(2) << "Failed to reset camera!";
     510            return;
     511        }
     512
     513        this->shakeDt_ = 0.0f;
     514        camera->setPosition(this->cameraOriginalPosition_);
     515        camera->setOrientation(this->cameraOriginalOrientation_);
    443516    }
    444517
Note: See TracChangeset for help on using the changeset viewer.