Applied-Energistics-2-tiler.../src/main/java/appeng/hooks/TickHandler.java
yueh 02ac8cf220 Refactored the logging
Using LogManager instead of FMLRelaunchLog to access the logger instance.
Added logging of the name of failed exports instead of exception.
Improved crafting log to include issuer including their location and the
requested item.
Removed superfluous FMLRelaunchLog instance.
Removed superfluous parameters for PlayerData constructor.
2016-01-01 02:55:36 +01:00

340 lines
8.3 KiB
Java

/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.hooks;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Stopwatch;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import net.minecraft.world.World;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.gameevent.TickEvent.Type;
import net.minecraftforge.fml.common.gameevent.TickEvent.WorldTickEvent;
import appeng.api.AEApi;
import appeng.api.networking.IGridNode;
import appeng.api.parts.CableRenderMode;
import appeng.api.util.AEColor;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.CommonHelper;
import appeng.core.sync.packets.PacketPaintedEntity;
import appeng.crafting.CraftingJob;
import appeng.me.Grid;
import appeng.me.NetworkList;
import appeng.tile.AEBaseTile;
import appeng.util.IWorldCallable;
import appeng.util.Platform;
public class TickHandler
{
public static final TickHandler INSTANCE = new TickHandler();
private final Queue<IWorldCallable<?>> serverQueue = new LinkedList<IWorldCallable<?>>();
private final Multimap<World, CraftingJob> craftingJobs = LinkedListMultimap.create();
private final WeakHashMap<World, Queue<IWorldCallable<?>>> callQueue = new WeakHashMap<World, Queue<IWorldCallable<?>>>();
private final HandlerRep server = new HandlerRep();
private final HandlerRep client = new HandlerRep();
private final HashMap<Integer, PlayerColor> cliPlayerColors = new HashMap<Integer, PlayerColor>();
private final HashMap<Integer, PlayerColor> srvPlayerColors = new HashMap<Integer, PlayerColor>();
private CableRenderMode crm = CableRenderMode.Standard;
public HashMap<Integer, PlayerColor> getPlayerColors()
{
if( Platform.isServer() )
{
return this.srvPlayerColors;
}
return this.cliPlayerColors;
}
public void addCallable( final World w, final IWorldCallable<?> c )
{
if( w == null )
{
this.serverQueue.add( c );
}
else
{
Queue<IWorldCallable<?>> queue = this.callQueue.get( w );
if( queue == null )
{
queue = new LinkedList<IWorldCallable<?>>();
this.callQueue.put( w, queue );
}
queue.add( c );
}
}
public void addInit( final AEBaseTile tile )
{
if( Platform.isServer() ) // for no there is no reason to care about this on the client...
{
this.getRepo().tiles.add( tile );
}
}
private HandlerRep getRepo()
{
if( Platform.isServer() )
{
return this.server;
}
return this.client;
}
public void addNetwork( final Grid grid )
{
if( Platform.isServer() ) // for no there is no reason to care about this on the client...
{
this.getRepo().networks.add( grid );
}
}
public void removeNetwork( final Grid grid )
{
if( Platform.isServer() ) // for no there is no reason to care about this on the client...
{
this.getRepo().networks.remove( grid );
}
}
public Iterable<Grid> getGridList()
{
return this.getRepo().networks;
}
public void shutdown()
{
this.getRepo().clear();
}
@SubscribeEvent
public void unloadWorld( final WorldEvent.Unload ev )
{
if( Platform.isServer() ) // for no there is no reason to care about this on the client...
{
final LinkedList<IGridNode> toDestroy = new LinkedList<IGridNode>();
for( final Grid g : this.getRepo().networks )
{
for( final IGridNode n : g.getNodes() )
{
if( n.getWorld() == ev.world )
{
toDestroy.add( n );
}
}
}
for( final IGridNode n : toDestroy )
{
n.destroy();
}
}
}
@SubscribeEvent
public void onChunkLoad( final ChunkEvent.Load load )
{
for( final Object te : load.getChunk().getTileEntityMap().values() )
{
if( te instanceof AEBaseTile )
{
( (AEBaseTile) te ).onChunkLoad();
}
}
}
@SubscribeEvent
public void onTick( final TickEvent ev )
{
if( ev.type == Type.CLIENT && ev.phase == Phase.START )
{
this.tickColors( this.cliPlayerColors );
final CableRenderMode currentMode = AEApi.instance().partHelper().getCableRenderMode();
if( currentMode != this.crm )
{
this.crm = currentMode;
CommonHelper.proxy.triggerUpdates();
}
}
if( ev.type == Type.WORLD && ev.phase == Phase.END )
{
final WorldTickEvent wte = (WorldTickEvent) ev;
synchronized( this.craftingJobs )
{
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if( !jobSet.isEmpty() )
{
final int simTime = Math.max( 1, AEConfig.instance.craftingCalculationTimePerTick / jobSet.size() );
final Iterator<CraftingJob> i = jobSet.iterator();
while( i.hasNext() )
{
final CraftingJob cj = i.next();
if( !cj.simulateFor( simTime ) )
{
i.remove();
}
}
}
}
}
// for no there is no reason to care about this on the client...
else if( ev.type == Type.SERVER && ev.phase == Phase.END )
{
this.tickColors( this.srvPlayerColors );
// ready tiles.
final HandlerRep repo = this.getRepo();
while( !repo.tiles.isEmpty() )
{
final AEBaseTile bt = repo.tiles.poll();
if( !bt.isInvalid() )
{
bt.onReady();
}
}
// tick networks.
for( final Grid g : this.getRepo().networks )
{
g.update();
}
// cross world queue.
this.processQueue( this.serverQueue, null );
}
// world synced queue(s)
if( ev.type == Type.WORLD && ev.phase == Phase.START )
{
final World world = ( (WorldTickEvent) ev ).world;
final Queue<IWorldCallable<?>> queue = this.callQueue.get( world );
this.processQueue( queue, world );
}
}
private void tickColors( final HashMap<Integer, PlayerColor> playerSet )
{
final Iterator<PlayerColor> i = playerSet.values().iterator();
while( i.hasNext() )
{
final PlayerColor pc = i.next();
if( pc.ticksLeft <= 0 )
{
i.remove();
}
pc.ticksLeft--;
}
}
private void processQueue( final Queue<IWorldCallable<?>> queue, final World world )
{
if( queue == null )
{
return;
}
final Stopwatch sw = Stopwatch.createStarted();
IWorldCallable<?> c = null;
while( ( c = queue.poll() ) != null )
{
try
{
c.call( world );
if( sw.elapsed( TimeUnit.MILLISECONDS ) > 50 )
{
break;
}
}
catch( final Exception e )
{
AELog.debug( e );
}
}
// long time = sw.elapsed( TimeUnit.MILLISECONDS );
// if ( time > 0 )
// AELog.info( "processQueue Time: " + time + "ms" );
}
public void registerCraftingSimulation( final World world, final CraftingJob craftingJob )
{
synchronized( this.craftingJobs )
{
this.craftingJobs.put( world, craftingJob );
}
}
private static class HandlerRep
{
private Queue<AEBaseTile> tiles = new LinkedList<AEBaseTile>();
private Collection<Grid> networks = new NetworkList();
private void clear()
{
this.tiles = new LinkedList<AEBaseTile>();
this.networks = new NetworkList();
}
}
public static class PlayerColor
{
public final AEColor myColor;
private final int myEntity;
private int ticksLeft;
public PlayerColor( final int id, final AEColor col, final int ticks )
{
this.myEntity = id;
this.myColor = col;
this.ticksLeft = ticks;
}
public PacketPaintedEntity getPacket()
{
return new PacketPaintedEntity( this.myEntity, this.myColor, this.ticksLeft );
}
}
}