1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-06-25 22:52:51 +00:00

Begin investigations into reducing ticking of TEs

- Move IDirectionalTile constraint from IPeripheralTile to
   TilePeripheralBase.
 - Make *WiredModemFull no longer inherit from *PeripheralBase. While
   there is still some shared logic (namely in the syncing of "anim"),
   it's largely fine as we don't store label or direction in NBT.
 - Add a TickScheduler. This is a thread-safe version of
   World.scheduleUpdate. We simply build a set of all TEs, and schedule
   them to be updated the next tick.
 - Make ModemState receive an "onChanged" listener, which is fired
   whenever the modem changes.
 - Make WiredModemFull no longer tick, instead scheduling updates when
   it is first loaded and whenever the modem changes.
This commit is contained in:
SquidDev 2019-01-19 10:16:41 +00:00
parent 443e0f8f76
commit a8dad23fa3
7 changed files with 154 additions and 56 deletions

View File

@ -8,19 +8,15 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyDirection; import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;

View File

@ -7,15 +7,17 @@
package dan200.computercraft.shared.peripheral.common; package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
public interface IPeripheralTile extends IDirectionalTile public interface IPeripheralTile
{ {
PeripheralType getPeripheralType(); PeripheralType getPeripheralType();
IPeripheral getPeripheral( EnumFacing side ); IPeripheral getPeripheral( EnumFacing side );
String getLabel(); default String getLabel()
{
return null;
}
} }

View File

@ -7,6 +7,7 @@
package dan200.computercraft.shared.peripheral.common; package dan200.computercraft.shared.peripheral.common;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -17,8 +18,7 @@ import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public abstract class TilePeripheralBase extends TileGeneric public abstract class TilePeripheralBase extends TileGeneric implements IPeripheralTile, ITickable, IDirectionalTile
implements IPeripheralTile, ITickable
{ {
// Statics // Statics

View File

@ -14,16 +14,27 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class ModemState public class ModemState
{ {
private boolean open = false; private final Runnable onChanged;
private AtomicBoolean changed = new AtomicBoolean( true ); private final AtomicBoolean changed = new AtomicBoolean( true );
private boolean open = false;
private final IntSet channels = new IntOpenHashSet(); private final IntSet channels = new IntOpenHashSet();
public ModemState()
{
this.onChanged = null;
}
public ModemState( Runnable onChanged )
{
this.onChanged = onChanged;
}
private void setOpen( boolean open ) private void setOpen( boolean open )
{ {
if( this.open == open ) return; if( this.open == open ) return;
this.open = open; this.open = open;
this.changed.set( true ); if( !changed.getAndSet( true ) && onChanged != null ) onChanged.run();
} }
public boolean pollChanged() public boolean pollChanged()

View File

@ -7,20 +7,21 @@
package dan200.computercraft.shared.peripheral.modem.wired; package dan200.computercraft.shared.peripheral.modem.wired;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralBase; import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Random;
public class BlockWiredModemFull extends BlockPeripheralBase public class BlockWiredModemFull extends BlockGeneric
{ {
// Statics // Statics
@ -34,6 +35,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
public BlockWiredModemFull() public BlockWiredModemFull()
{ {
super( Material.ROCK );
setHardness( 1.5f ); setHardness( 1.5f );
setTranslationKey( "computercraft:wired_modem_full" ); setTranslationKey( "computercraft:wired_modem_full" );
setCreativeTab( ComputerCraft.mainCreativeTab ); setCreativeTab( ComputerCraft.mainCreativeTab );
@ -43,12 +45,6 @@ public class BlockWiredModemFull extends BlockPeripheralBase
); );
} }
@Override
protected IBlockState getDefaultBlockState( PeripheralType type, EnumFacing placedSide )
{
return getDefaultState();
}
@Nonnull @Nonnull
@Override @Override
protected BlockStateContainer createBlockState() protected BlockStateContainer createBlockState()
@ -74,7 +70,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
if( te instanceof TileWiredModemFull ) if( te instanceof TileWiredModemFull )
{ {
TileWiredModemFull modem = (TileWiredModemFull) te; TileWiredModemFull modem = (TileWiredModemFull) te;
int anim = modem.getAnim(); int anim = modem.getState();
state = state state = state
.withProperty( Properties.MODEM_ON, (anim & 1) != 0 ) .withProperty( Properties.MODEM_ON, (anim & 1) != 0 )
.withProperty( Properties.PERIPHERAL_ON, (anim & 2) != 0 ); .withProperty( Properties.PERIPHERAL_ON, (anim & 2) != 0 );
@ -84,19 +80,20 @@ public class BlockWiredModemFull extends BlockPeripheralBase
} }
@Override @Override
public PeripheralType getPeripheralType( int damage ) public void updateTick( World world, BlockPos pos, IBlockState state, Random rand )
{ {
return PeripheralType.WiredModemFull; TileEntity te = world.getTileEntity( pos );
if( te instanceof TileWiredModemFull ) ((TileWiredModemFull) te).updateTick();
} }
@Override @Override
public PeripheralType getPeripheralType( IBlockState state ) protected TileGeneric createTile( IBlockState state )
{ {
return PeripheralType.WiredModemFull; return new TileWiredModemFull();
} }
@Override @Override
public TilePeripheralBase createTile( PeripheralType type ) protected TileGeneric createTile( int damage )
{ {
return new TileWiredModemFull(); return new TileWiredModemFull();
} }

View File

@ -12,8 +12,11 @@ import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.TickScheduler;
import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@ -30,7 +33,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
public class TileWiredModemFull extends TilePeripheralBase public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
{ {
private static class FullElement extends WiredModemElement private static class FullElement extends WiredModemElement
{ {
@ -85,10 +88,12 @@ public class TileWiredModemFull extends TilePeripheralBase
private boolean m_destroyed = false; private boolean m_destroyed = false;
private boolean m_connectionsFormed = false; private boolean m_connectionsFormed = false;
private final ModemState m_modemState = new ModemState(); private final ModemState m_modemState = new ModemState( () -> TickScheduler.schedule( this ) );
private final WiredModemElement m_element = new FullElement( this ); private final WiredModemElement m_element = new FullElement( this );
private final IWiredNode m_node = m_element.getNode(); private final IWiredNode m_node = m_element.getNode();
private int m_state = 0;
public TileWiredModemFull() public TileWiredModemFull()
{ {
for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral(); for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral();
@ -128,17 +133,6 @@ public class TileWiredModemFull extends TilePeripheralBase
remove(); remove();
} }
@Override
public EnumFacing getDirection()
{
return EnumFacing.NORTH;
}
@Override
public void setDirection( EnumFacing dir )
{
}
@Override @Override
public void onNeighbourChange() public void onNeighbourChange()
{ {
@ -231,27 +225,50 @@ public class TileWiredModemFull extends TilePeripheralBase
return nbt; return nbt;
} }
protected void updateAnim() public int getState()
{ {
int anim = 0; return m_state;
if( m_modemState.isOpen() ) anim |= 1; }
if( m_peripheralAccessAllowed ) anim |= 2;
setAnim( anim ); private void updateState()
{
int state = 0;
if( m_modemState.isOpen() ) state |= 1;
if( m_peripheralAccessAllowed ) state |= 2;
if( state != m_state )
{
m_state = state;
updateBlock();
}
}
@Override
protected void writeDescription( @Nonnull NBTTagCompound nbt )
{
super.writeDescription( nbt );
nbt.setInteger( "state", m_state );
} }
@Override @Override
public final void readDescription( @Nonnull NBTTagCompound nbt ) public final void readDescription( @Nonnull NBTTagCompound nbt )
{ {
super.readDescription( nbt ); super.readDescription( nbt );
m_state = nbt.getInteger( "state" );
updateBlock(); updateBlock();
} }
@Override @Override
public void update() public void onLoad()
{
super.onLoad();
if( !world.isRemote ) world.scheduleUpdate( pos, getBlockType(), 0 );
}
protected void updateTick()
{ {
if( !getWorld().isRemote ) if( !getWorld().isRemote )
{ {
if( m_modemState.pollChanged() ) updateAnim(); if( m_modemState.pollChanged() ) updateState();
if( !m_connectionsFormed ) if( !m_connectionsFormed )
{ {
@ -268,8 +285,6 @@ public class TileWiredModemFull extends TilePeripheralBase
} }
} }
} }
super.update();
} }
private void connectionsChanged() private void connectionsChanged()
@ -291,7 +306,6 @@ public class TileWiredModemFull extends TilePeripheralBase
} }
} }
// private stuff
private void togglePeripheralAccess() private void togglePeripheralAccess()
{ {
if( !m_peripheralAccessAllowed ) if( !m_peripheralAccessAllowed )
@ -317,7 +331,7 @@ public class TileWiredModemFull extends TilePeripheralBase
m_node.updatePeripherals( Collections.emptyMap() ); m_node.updatePeripherals( Collections.emptyMap() );
} }
updateAnim(); updateState();
} }
private Set<String> getConnectedPeripheralNames() private Set<String> getConnectedPeripheralNames()
@ -349,7 +363,7 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
// If there are no peripherals then disable access and update the display state. // If there are no peripherals then disable access and update the display state.
m_peripheralAccessAllowed = false; m_peripheralAccessAllowed = false;
updateAnim(); updateState();
} }
m_node.updatePeripherals( peripherals ); m_node.updatePeripherals( peripherals );
@ -360,7 +374,8 @@ public class TileWiredModemFull extends TilePeripheralBase
@Override @Override
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing ) public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )
{ {
return capability == CapabilityWiredElement.CAPABILITY || super.hasCapability( capability, facing ); if( capability == CapabilityWiredElement.CAPABILITY ) return !m_destroyed;
return super.hasCapability( capability, facing );
} }
@Nullable @Nullable
@ -369,6 +384,7 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
if( capability == CapabilityWiredElement.CAPABILITY ) if( capability == CapabilityWiredElement.CAPABILITY )
{ {
if( m_destroyed ) return null;
return CapabilityWiredElement.CAPABILITY.cast( m_element ); return CapabilityWiredElement.CAPABILITY.cast( m_element );
} }
@ -377,9 +393,17 @@ public class TileWiredModemFull extends TilePeripheralBase
// IPeripheralTile // IPeripheralTile
@Override
public PeripheralType getPeripheralType()
{
return PeripheralType.WiredModemFull;
}
@Override @Override
public IPeripheral getPeripheral( EnumFacing side ) public IPeripheral getPeripheral( EnumFacing side )
{ {
if( m_destroyed ) return null;
WiredModemPeripheral peripheral = m_modems[side.ordinal()]; WiredModemPeripheral peripheral = m_modems[side.ordinal()];
if( peripheral == null ) if( peripheral == null )
{ {

View File

@ -0,0 +1,68 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.util;
import com.google.common.collect.MapMaker;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.block.Block;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
/**
* A thread-safe version of {@link World#scheduleUpdate(BlockPos, Block, int)}.
*
* We use this when modems and other peripherals change a block in a different thread.
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
public final class TickScheduler
{
private TickScheduler()
{
}
private static final Set<TileEntity> toTick = Collections.newSetFromMap(
new MapMaker()
.weakKeys()
.makeMap()
);
public static void schedule( TileGeneric tile )
{
World world = tile.getWorld();
if( world != null && !world.isRemote ) toTick.add( tile );
}
@SubscribeEvent
public static void tick( TickEvent.ServerTickEvent event )
{
if( event.phase != TickEvent.Phase.START ) return;
Iterator<TileEntity> iterator = toTick.iterator();
while( iterator.hasNext() )
{
TileEntity tile = iterator.next();
iterator.remove();
World world = tile.getWorld();
BlockPos pos = tile.getPos();
if( world != null && pos != null && world.isBlockLoaded( pos ) && world.getTileEntity( pos ) == tile )
{
world.scheduleUpdate( pos, tile.getBlockType(), 0 );
}
}
}
}