Package org.groovymud.engine

Source Code of org.groovymud.engine.JMudEngine

package org.groovymud.engine;

/* Copyright 2008 Matthew Corby-Eaglen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import net.wimpi.telnetd.TelnetD;

import org.apache.log4j.Logger;
import org.groovymud.engine.event.HeartBeatListener;
import org.groovymud.object.MudObject;
import org.groovymud.object.alive.Player;
import org.groovymud.object.registry.MudObjectAttendant;
import org.groovymud.object.registry.Registry;
import org.groovymud.object.room.Room;
import org.groovymud.shell.telnetd.LoginShell;
import org.groovymud.shell.telnetd.ShellBridge;
import org.groovymud.utils.CountingMap;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* The mud engine is responsible for starting up the mud, shutting it down,
* distributing heartbeats, resetting rooms and registering player states.
*
* @author matt
*
*/
public abstract class JMudEngine extends Thread {

  private static final int HEARTBEATS_UNTIL_AUTOSAVE = 60;
  private static final int HEARTBEATS_UNTIL_RESET = 1200;

  private static final String NET_DEAD_STATUS = "net dead";

  protected static final int DEFAULT_MUD_HEARTBEAT_LENGTH_MS = 1000;

  private static TelnetD telnetDaemon;

  private Registry objectRegistry;

  private volatile boolean running;

  private final static Logger logger = Logger.getLogger(JMudEngine.class);

  private static AbstractApplicationContext context;

  private MudObjectAttendant objectAttendant;

  private CountingMap netDeadPlayers;

  private boolean shutdownRequested = false;

  private ExecutorService executor;

  public JMudEngine() {
    running = true;
  }

  public static void main(String[] args) {
    System.out.println("workspace.loc:" + System.getProperty("workspace.loc"));
    System.out.println("mavenrepo:" + System.getProperty("maven.repo"));
    System.out.println("mudspace:" + System.getProperty("mudspace"));

    context = new ClassPathXmlApplicationContext(new String[] { "org/groovymud/telnetdContext.xml", "org/groovymud/applicationContext.xml", "/commandAliases.xml" });
    context.registerShutdownHook();
    ShellBridge.setApplicationContext(context);

    JMudEngine engine = (JMudEngine) context.getBean("mudEngine");
    engine.setPriority(Thread.MAX_PRIORITY);
    engine.getExecutor().execute(engine);

    telnetDaemon.start();
  }

  public void run() {
    logger.info("GroovyMud up and running");
    int saveTime = 0;
    int resetTime = 0;
    while (isRunning()) {
      try {
        doHeartBeat();
        handleTheNetDead();
        checkPlayerHandles();

        if (saveTime++ == HEARTBEATS_UNTIL_AUTOSAVE) {
          savePlayers();
          saveTime = 0;
        }
        if (resetTime++ == HEARTBEATS_UNTIL_RESET) {
          resetRooms();
          resetTime = 0;
        }
        if (isShutdownRequested()) {
          createShutdownBehaviour().handleShutdown();
        }
        Thread.sleep(DEFAULT_MUD_HEARTBEAT_LENGTH_MS);
      } catch (InterruptedException e) {
        logger.error(e, e);
      }
    }

  }

  protected void resetRooms() {
    logger.info("Resetting rooms");
    Iterator<MudObject> i = getObjectRegistry().getMudObjects().iterator();
    while (i.hasNext()) {
      MudObject o = i.next();

      if (o instanceof Room) {
        ((Room) o).initialise();
      }
      Thread.yield();
    }

  }

  protected void savePlayers() {

    Iterator<LoginShell> i = getObjectRegistry().getActivePlayerHandles().iterator();
    if (i.hasNext()) {
      logger.info("auto saving..");
    }
    while (i.hasNext()) {
      LoginShell o = i.next();
      Player p = o.getPlayer();
      if (getObjectRegistry().getMudObject(p.getName()) != null) {
        getObjectAttendant().savePlayerData(p);
        try {
          o.getPlayer().getTerminalOutput().writeln("\r\nAuto Saving...");
        } catch (IOException e) {
          logger.error(e, e);
        }
      }
    }
  }

  protected void checkPlayerHandles() {
    CountingMap netDead = getNetDeadPlayers();
    Set<Player> totallyDead = netDead.getKeysAbove(30);

    for (Player p : totallyDead) {
      p.removeStatus(NET_DEAD_STATUS);
      p.dest(false);
      getNetDeadPlayers().remove(p);
    }

  }

  protected void doHeartBeat() {
    Set<MudObject> objects = getObjectRegistry().getMudObjects();
    Iterator<MudObject> i = objects.iterator();
    while (i.hasNext()) {
      MudObject o = i.next();

      if (o instanceof HeartBeatListener) {
        try {
          ((HeartBeatListener) o).heartBeat();
        } catch (Exception e) {
          // ^^ ick but we don't want to break the whole hearbeat
          // system because of
          // one object's error now do we?
          logger.error(e, e);
        }
      }
      Thread.yield();
    }

  }

  protected void handleTheNetDead() {

    Iterator<LoginShell> x = new HashSet<LoginShell>(getObjectRegistry().getActivePlayerHandles()).iterator();
    CountingMap netDead = getNetDeadPlayers();
    while (x.hasNext()) {
      LoginShell shell = x.next();
      if (!shell.getConnection().isActive()) {
        Player p = getObjectRegistry().getPlayerByHandle(shell);
        if (!netDead.containsKey(p)) {
          // not a good way to do it.. but how.. ?
          logger.info(p.getName() + " is net dead..");
          p.addStatus(NET_DEAD_STATUS);
        }
        netDead.increment(p);
      }
    }
  }

  public boolean isRunning() {
    return running;
  }

  public void setRunning(boolean running) {
    this.running = running;
  }

  public void requestShutDown(Player requester) {
    logger.info("shutdown requested!!!");

    shutdownRequested = true;

  }

  public static AbstractApplicationContext getContext() {
    return context;
  }

  public Registry getObjectRegistry() {
    return objectRegistry;
  }

  public void setObjectRegistry(Registry registry) {
    this.objectRegistry = registry;
  }

  public MudObjectAttendant getObjectAttendant() {
    return objectAttendant;
  }

  public void setObjectAttendant(MudObjectAttendant objectAttendant) {
    this.objectAttendant = objectAttendant;
  }

  public TelnetD getTelnetDaemon() {
    return telnetDaemon;
  }

  public void setTelnetDaemon(TelnetD telnetDeamon) {
    JMudEngine.telnetDaemon = telnetDeamon;
  }

  public CountingMap getNetDeadPlayers() {
    return netDeadPlayers;
  }

  public void setNetDeadPlayers(CountingMap netDeadPlayers) {
    this.netDeadPlayers = netDeadPlayers;
  }

  public void setShutdownRequested(boolean shutdownRequested) {
    this.shutdownRequested = shutdownRequested;
  }

  public boolean isShutdownRequested() {
    return shutdownRequested;
  }

  protected void shutdownNow() {
    logger.info("shutdownNow called");
    destAllPlayers();
    getTelnetDaemon().stop();
    this.setRunning(false);
    logger.info("shudownNow complete");
    System.exit(0);
  }

  protected void destAllPlayers() {
    Iterator<LoginShell> x = new HashSet<LoginShell>(getObjectRegistry().getActivePlayerHandles()).iterator();
    while (x.hasNext()) {
      LoginShell shell = x.next();
      if (shell.getConnection().isActive()) {
        Player p = getObjectRegistry().getPlayerByHandle(shell);
        p.dest(false);
      }
    }
  }

  public abstract ShutdownBehaviour createShutdownBehaviour();

  public void setExecutor(ExecutorService executor) {
    this.executor = executor;
  }

  public ExecutorService getExecutor() {
    return executor;
  }

}
TOP

Related Classes of org.groovymud.engine.JMudEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.