/*
* This file is part of aion-unique <aion-unique.org>.
*
* aion-unique is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aion-unique is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with aion-unique. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aionemu.gameserver.services;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.network.aion.serverpackets.SM_WEATHER;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.MapRegion;
import com.aionemu.gameserver.world.World;
import com.aionemu.gameserver.world.WorldMap;
import com.google.inject.Inject;
/**
* This service in future should schedule job that is changing weather sometimes in region and probably sends to all
* players
*
* @author ATracer
* @author Kwazar
*/
public class WeatherService
{
@Inject
private World world;
private final long WEATHER_DURATION = 2 * 60 * 60 * 1000; // 2 hours
private final long CHECK_INTERVAL = 1 * 2 * 60 * 1000; // 2 mins
private Map<WeatherKey, Integer> worldWeathers;
public WeatherService()
{
worldWeathers = new HashMap<WeatherKey, Integer>();
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable(){
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
checkWeathersTime();
}
}, CHECK_INTERVAL, CHECK_INTERVAL);
}
/**
* Key class used to store date of key creation (for rolling weather usage)
*
* @author Kwazar
*
*/
private class WeatherKey
{
/**
* Date of creation of the weather for this region
*/
private Date created;
/**
* Region affected to this type of weather (in worldWeathers map)
*/
private WorldMap map;
/**
* Parametered Constructor
*
* @param date
* creation date
* @param worldMap
* map to link
*/
public WeatherKey(Date date, WorldMap worldMap)
{
this.created = date;
this.map = worldMap;
}
/**
* @return the map
*/
public WorldMap getMap()
{
return map;
}
/**
* Returns <code>true</code> if the key is out of date relating to constant WEATHER_DURATION, <code>false</code>
* either
*
* @return true or false
*/
public boolean isOutDated()
{
Date now = new Date();
long nowTime = now.getTime();
long createdTime = created.getTime();
long delta = nowTime - createdTime;
return (delta > WEATHER_DURATION);
}
}
/**
* triggered every CHECK_INTERVAL
*/
private void checkWeathersTime()
{
List<WeatherKey> toBeRefreshed = new ArrayList<WeatherKey>();
for(WeatherKey key : worldWeathers.keySet())
{
if(key.isOutDated())
{
toBeRefreshed.add(key);
}
}
for(WeatherKey key : toBeRefreshed)
{
worldWeathers.remove(key);
onWeatherChange(key.getMap(), null);
}
}
/**
* @return a random WeatherType as an integer (0->8)
*/
private int getRandomWeather()
{
return Rnd.get(0, 8);
}
/**
* When a player connects, it loads his weather
*
* @param player
*/
public void loadWeather(Player player)
{
WorldMap worldMap = player.getActiveRegion().getParent().getParent();
onWeatherChange(worldMap, player);
}
/**
* Return the correct key from the worldWeathers Map by the worldMap
*
* @param map
* @return
*/
private WeatherKey getKeyFromMapByWorldMap(WorldMap map)
{
for(WeatherKey key : worldWeathers.keySet())
{
if(key.getMap().equals(map))
{
return key;
}
}
WeatherKey newKey = new WeatherKey(new Date(), map);
worldWeathers.put(newKey, getRandomWeather());
return newKey;
}
/**
* @param worldMap
* @return the WeatherType of the {@link WorldMap} for this session
*/
private int getWeatherTypeByRegion(WorldMap worldMap)
{
WeatherKey key = getKeyFromMapByWorldMap(worldMap);
return worldWeathers.get(key).intValue();
}
/**
* Allows server to reinitialize Weathers for all regions
*/
public void resetWeather()
{
Set<WeatherKey> loadedWeathers = new HashSet<WeatherKey>(worldWeathers.keySet());
worldWeathers.clear();
for(WeatherKey key : loadedWeathers)
{
onWeatherChange(key.getMap(), null);
}
}
/**
* Allows server to change a specific {@link MapRegion}'s WeatherType
*
* @param regionId
* the regionId to be changed of WeatherType
* @param weatherType
* the new WeatherType
*/
public void changeRegionWeather(int regionId, Integer weatherType)
{
WorldMap worldMap = world.getWorldMap(regionId);
WeatherKey key = getKeyFromMapByWorldMap(worldMap);
worldWeathers.put(key, weatherType);
onWeatherChange(worldMap, null);
}
/**
*
* triggers the update of weather to all players
*
* @param world
* @param worldMap
* @param player
* if null -> weather is broadcasted to all players in world
*/
private void onWeatherChange(WorldMap worldMap, Player player)
{
if(player == null)
{
for(Iterator<Player> playerIterator = world.getPlayersIterator(); playerIterator.hasNext();)
{
Player currentPlayer = playerIterator.next();
if(!currentPlayer.isSpawned())
continue;
WorldMap currentPlayerWorldMap = currentPlayer.getActiveRegion().getParent().getParent();
if(currentPlayerWorldMap.equals(worldMap))
{
PacketSendUtility.sendPacket(currentPlayer, new SM_WEATHER(
getWeatherTypeByRegion(currentPlayerWorldMap)));
}
}
}
else
{
PacketSendUtility.sendPacket(player, new SM_WEATHER(getWeatherTypeByRegion(worldMap)));
}
}
}