Пример #1
0
        /// <summary>
        ///  Attach a new state to a world vector.
        /// </summary>
        /// <param name="state">The world state used ot init the vector.</param>
        public WorldVector(WorldState state)
        {
            if (!state.IsImmutable)
            {
                throw new ApplicationException("WorldState must be immutable to be added to vector.");
            }

            State = state;
        }
Пример #2
0
        /// <summary>
        /// Processes turns in a phase manner.  After 10 calls to ProcessTurn
        /// all 10 phases will be complete and the method will have completed
        /// one game tick.
        /// </summary>
        /// <returns>True if a tick has been processed, false otherwise.</returns>
        public Boolean ProcessTurn()
        {
            // shutdownError and invalidPeerError are two errors that get set from
            // deep in the system.  We process them here because it is a clean place
            // to restart the game since we aren't in the middle of any phases.
            // This is just a mechanism for cleanly throwing an error from a known good
            // location.
            if (_shutdownError)
            {
                _shutdownError = false;
                throw new ShutdownFailureException();
            }

            if (_invalidPeerError)
            {
                _invalidPeerError = false;
                throw new InvalidPeerException();
            }

            // We break the main processing of the game into 10 phases that have been tuned to each
            // take roughly the same amount of time.  We paint the screen in between each one.  This way
            // We can have a constant frame rate and incrementally do the engine processing we need to
            // do.
            // After we do all 10 phases we've done one game "tick".  We can do two ticks a second which means
            // we have a frame rate of 20.
            switch (_turnPhase)
            {
                case 0:
                    // If we are in ecosystem mode, we want to save the game state periodically in case the user
                    // shuts down the screensaver by pressing ctl-alt-del which just kills the process.  This way
                    // we won't have lost too much processing time.
                    // We always want to save on the tick after we've reported so we don't get our state messed up
                    // on the server.  For example: never start the game in a state that was before the information
                    // was sent to the server because the server will think we're corrupted.
                    if (_logState ||
                        (_ecosystemMode && _populationData.IsReportingTick(CurrentVector.State.TickNumber - 1)))
                    {
                        Debug.WriteLine("Saving state.");
                        serializeState(_currentStateFileName);
                    }

                    // Give 1/5 of the animals a chance to do their processing
                    Scheduler.Tick();
                    break;

                case 1:
                    // Give 1/5 of the animals a chance to do their processing
                    Scheduler.Tick();
                    break;

                case 2:
                    // Give 1/5 of the animals a chance to do their processing
                    Scheduler.Tick();
                    break;

                case 3:
                    // Give 1/5 of the animals a chance to do their processing
                    Scheduler.Tick();
                    break;

                case 4:
                    // Give 1/5 of the animals a chance to do their processing
                    Scheduler.Tick();
                    break;

                case 5:
                    // Get all the actions that the animals want to perform in this tick.
                    TickActions act = _scheduler.GatherTickActions();

                    CurrentVector.Actions = act;

                    // Create a mutable version of the world state that we'll change to create the next
                    // world state.
                    _newWorldState = (WorldState) CurrentVector.State.DuplicateMutable();
                    _newWorldState.TickNumber = _newWorldState.TickNumber + 1;
                    _populationData.BeginTick(_newWorldState.TickNumber, CurrentVector.State.StateGuid);

                    // Remove any organisms queued to be removed
                    removeOrganismsFromQueue();

                    // We take a snapshot of the organism IDs since we do several foreach loops
                    // and change the state, which causes exceptions to occur
                    _organismIDList = new string[_newWorldState.OrganismIDs.Count];
                    _newWorldState.OrganismIDs.CopyTo(_organismIDList, 0);
                    killDiseasedOrganisms2();
                    break;

                case 6:
                    Debug.Assert(_newWorldState != null, "Worldstate did not get created for this tick");

                    // Do this first, since it always must happen so that things (like growing)
                    // won't happen if there isn't enough energy
                    burnBaseEnergy();

                    // Do attacks before movement so that when a carnivore asks if it can attack
                    // they actually get to hit the target before it moves
                    doAttacks();
                    doDefends();
                    changeMovementVectors();
                    break;

                case 7:
                    moveAnimals();
                    break;

                case 8:
                    doBites();
                    growAllOrganisms();
                    incubate();
                    startReproduction();
                    heal();
                    break;

                case 9:
                    // Do this last so that the plant always starts charged up,
                    // and has to operate with what it has for the next turn
                    giveEnergyToPlants();

                    // Teleport after all actions have been processed so that there are
                    // no single turn pending actions left for the organism.
                    teleportOrganisms();

                    // Insert any new organisms
                    insertOrganismsFromQueue();

                    // Set Antenna States
                    doAntennas();

                    // We're done changing the state, now make it immutable
                    _newWorldState.MakeImmutable();
                    Debug.Assert(_newWorldState.Organisms.Count == Scheduler.Organisms.Count);

                    WorldVector vector = new WorldVector(_newWorldState);
                    CurrentVector = vector;

                    _scheduler.CurrentState = _newWorldState;
                    _populationData.EndTick(_newWorldState.TickNumber);

                    _newWorldState = null;
                    break;
            }

            _turnPhase++;
            if (_turnPhase == 10)
            {
                _turnPhase = 0;
                return true;
            }
            return false;
        }
Пример #3
0
        /// <summary>
        ///  Constructs a new game engine.
        /// </summary>
        /// <param name="dataPath">The path to save game directory.</param>
        /// <param name="useNetwork">Controls the usage of the network engine.</param>
        /// <param name="deserializeState">Controls if the state is deserialized or not.</param>
        /// <param name="fileName">The path to the state file.</param>
        /// <param name="reportData">Determines if data should be reported.</param>
        /// <param name="leds">Provides a listing of game leds that can be used.</param>
        /// <param name="trackLastRun">Controls whether the PAC keeps track of the last run creature for blacklisting.</param>
        private GameEngine(string dataPath, bool useNetwork, bool deserializeState, string fileName, bool reportData,
            TerrariumLed[] leds, bool trackLastRun)
        {
            _ledIndicators = leds;
            _currentStateFileName = fileName;

            // test to make sure we're not violating any constraints by current
            // physics settings in the engine.
            EngineSettings.EngineSettingsAsserts();

            // Calculate quanta and worldsize if we haven't done so yet
            if (_reloadSettings)
                CalculateWorldSize();

            _pac = new PrivateAssemblyCache(dataPath, fileName, true, trackLastRun);

            // Reset the appdomain policy since we changed the location of the organism dlls
            // This must be done before any animals are loaded in any way.  Make sure this call stays
            // as soon as possible
            AppDomain.CurrentDomain.SetAppDomainPolicy(SecurityUtils.MakePolicyLevel(_pac.AssemblyDirectory));

            _usingNetwork = useNetwork;
            _populationData = new PopulationData(reportData, leds[(int) LedIndicators.ReportWebService]);

            // Should only happen if an exception prevented a previous attempt to start a game
            if (AppMgr.CurrentScheduler != null)
            {
                AppMgr.DestroyScheduler();
            }

            // Create a scheduler that manages giving the creatures timeslices
            _scheduler = AppMgr.CreateSameDomainScheduler(this);
            _scheduler.Quantum = _organismQuanta;

            if (useNetwork)
            {
                // Required to start up the network listeners
                _networkEngine = new NetworkEngine();
            }

            WorldState currentState;
            Boolean successfulDeserialization = false;
            if (deserializeState && File.Exists(fileName))
            {
                try
                {
                    if (_pac.LastRun.Length != 0)
                    {
                        // The process was killed while an organism was being run, blacklist it
                        // Since this potentially means the animal hung the game.
                        _pac.BlacklistAssemblies(new string[] {_pac.LastRun});
                    }
                    this.deserializeState(fileName);
                    currentState = CurrentVector.State;
                    _scheduler.CurrentState = currentState;
                    _scheduler.CompleteOrganismDeserialization();
                    successfulDeserialization = true;
                }
                catch (Exception e)
                {
                    ErrorLog.LogHandledException(e);
                }
            }

            if (successfulDeserialization) return;

            // Set up initial world state
            currentState = new WorldState(GridWidth, GridHeight);
            currentState.TickNumber = 0;
            currentState.StateGuid = Guid.NewGuid();
            currentState.Teleporter = new Teleporter(AnimalCount/EngineSettings.NumberOfAnimalsPerTeleporter);
            currentState.MakeImmutable();

            WorldVector vector = new WorldVector(currentState);
            CurrentVector = vector;
            _scheduler.CurrentState = currentState;
        }
Пример #4
0
        /// <summary>
        ///  Copies the object, but not the isImmutable bit.  Makes a newly
        ///  immutable copy.
        /// </summary>
        /// <returns>A new WorldState object that is newly mutable.</returns>
        public object DuplicateMutable()
        {
            var newState = new WorldState(_gridWidth, _gridHeight);

            foreach (OrganismState state in Organisms)
            {
                var newOrganismState = state.CloneMutable();
                Debug.Assert(newOrganismState != null, "Organism State is null in WorldState.DuplicateMutable()");
                Debug.Assert(newOrganismState.ID != null, "Organism State ID is null in WorldState.DuplicateMutable()");
                newState._organisms.Add(newOrganismState.ID, newOrganismState);
            }

            newState._tickNumber = _tickNumber;
            newState._stateGuid = _stateGuid;
            if (_teleporter != null)
            {
                newState._teleporter = _teleporter.Clone();
            }

            return newState;
        }