├── .gitignore ├── lib ├── Essentials.jar ├── MyWorlds-1.67.jar ├── SignLink-1.34.jar └── bukkit-1.7.2-R0.4-20140216.011848-2.jar ├── release └── TrainCarts-1.73.1-SNAPSHOT.jar ├── src └── main │ └── java │ ├── com │ └── bergerkiller │ │ └── bukkit │ │ └── tc │ │ ├── actions │ │ ├── GroupActionJump.java │ │ ├── WaitAction.java │ │ ├── BlockAction.java │ │ ├── GroupActionWaitForever.java │ │ ├── GroupActionSizzle.java │ │ ├── GroupActionWaitTicks.java │ │ ├── GroupActionWaitDelay.java │ │ ├── MovementAction.java │ │ ├── GroupActionWaitTill.java │ │ ├── BlockActionSetLevers.java │ │ ├── MemberActionWaitDistance.java │ │ ├── GroupActionWaitState.java │ │ ├── Action.java │ │ ├── GroupActionRefill.java │ │ ├── GroupAction.java │ │ ├── MemberActionWaitLocation.java │ │ ├── MemberActionLaunchDirection.java │ │ ├── MemberAction.java │ │ ├── MemberActionLaunchLocation.java │ │ ├── GroupActionWaitPathFinding.java │ │ ├── MemberActionWaitOccupied.java │ │ └── MemberActionLaunch.java │ │ ├── GroupUnloadedException.java │ │ ├── signactions │ │ ├── SignActionType.java │ │ ├── SignActionTrigger.java │ │ ├── SignActionMode.java │ │ ├── SignActionDestroy.java │ │ ├── SignActionWait.java │ │ ├── SignActionJumper.java │ │ ├── SignActionLauncher.java │ │ ├── SignActionBlocker.java │ │ ├── SignActionProperties.java │ │ ├── SignActionTeleport.java │ │ ├── SignActionAnnounce.java │ │ ├── detector │ │ │ └── DetectorSignPair.java │ │ ├── SignActionCraft.java │ │ ├── SignActionEject.java │ │ ├── SignActionTicket.java │ │ ├── SignActionEffect.java │ │ ├── SignActionBlockChanger.java │ │ ├── SignActionFuel.java │ │ └── SignActionStation.java │ │ ├── MemberMissingException.java │ │ ├── rails │ │ ├── type │ │ │ ├── RailTypeDetector.java │ │ │ ├── RailTypeActivator.java │ │ │ ├── RailTypeNone.java │ │ │ ├── RailTypeCrossing.java │ │ │ ├── RailTypePowered.java │ │ │ └── RailTypeHorizontal.java │ │ └── logic │ │ │ ├── RailLogicGround.java │ │ │ ├── RailLogicVerticalSlopeUp.java │ │ │ ├── RailLogicAir.java │ │ │ ├── RailLogicVerticalSlopeDown.java │ │ │ └── RailLogicVertical.java │ │ ├── controller │ │ ├── MinecartPassengerNetwork.java │ │ ├── MinecartMemberInventory.java │ │ ├── components │ │ │ ├── SoundLoop.java │ │ │ ├── PoweredCartSoundLoop.java │ │ │ ├── BlockTrackerMember.java │ │ │ ├── ActionTrackerGroup.java │ │ │ ├── ActionTracker.java │ │ │ ├── ActionTrackerMember.java │ │ │ └── BlockTracker.java │ │ ├── type │ │ │ ├── MinecartMemberHopper.java │ │ │ ├── MinecartMemberRideable.java │ │ │ ├── MinecartMemberMobSpawner.java │ │ │ ├── MinecartMemberTNT.java │ │ │ └── MinecartMemberChest.java │ │ └── MemberConverter.java │ │ ├── properties │ │ ├── IPropertiesHolder.java │ │ ├── IParsable.java │ │ └── CartPropertiesStore.java │ │ ├── events │ │ ├── GroupEvent.java │ │ ├── MemberEvent.java │ │ ├── GroupRemoveEvent.java │ │ ├── GroupUnloadEvent.java │ │ ├── GroupCreateEvent.java │ │ ├── MemberRemoveEvent.java │ │ ├── TrainCartsListener.java │ │ ├── MemberSpawnEvent.java │ │ ├── GroupForceUpdateEvent.java │ │ ├── SignChangeActionEvent.java │ │ ├── MemberAddEvent.java │ │ ├── MemberBlockChangeEvent.java │ │ ├── MemberCoalUsedEvent.java │ │ └── GroupLinkEvent.java │ │ ├── utils │ │ ├── AveragedItemParser.java │ │ ├── SoftReference.java │ │ ├── GroundItemsState.java │ │ ├── BlockTimeoutMap.java │ │ ├── ChangingSign.java │ │ ├── ChunkArea.java │ │ ├── TrackWalkIterator.java │ │ └── GroundItemsInventory.java │ │ ├── detector │ │ └── DetectorListener.java │ │ ├── statements │ │ ├── StatementFuel.java │ │ ├── StatementPlayerItems.java │ │ ├── StatementBoolean.java │ │ ├── StatementVelocity.java │ │ ├── StatementTag.java │ │ ├── StatementDestination.java │ │ ├── StatementEmpty.java │ │ ├── StatementName.java │ │ ├── StatementDirection.java │ │ ├── StatementPermission.java │ │ ├── StatementOwners.java │ │ ├── StatementRandom.java │ │ ├── StatementType.java │ │ ├── StatementPassenger.java │ │ ├── StatementPlayerHand.java │ │ ├── StatementRedstone.java │ │ ├── StatementProperty.java │ │ ├── StatementMob.java │ │ └── StatementItems.java │ │ ├── TCPacketListener.java │ │ ├── pathfinding │ │ └── PathConnection.java │ │ ├── itemanimation │ │ ├── VirtualItem.java │ │ └── ItemAnimatedInventory.java │ │ ├── DirectionStatement.java │ │ ├── storage │ │ ├── OfflineSign.java │ │ └── OfflineMember.java │ │ ├── Localization.java │ │ ├── InteractType.java │ │ └── Direction.java │ └── plugin.yml ├── .gitattributes ├── README.MD └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | target/* 3 | .classpath 4 | .project 5 | bin 6 | 7 | /target 8 | -------------------------------------------------------------------------------- /lib/Essentials.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergerkiller/TrainCarts/HEAD/lib/Essentials.jar -------------------------------------------------------------------------------- /lib/MyWorlds-1.67.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergerkiller/TrainCarts/HEAD/lib/MyWorlds-1.67.jar -------------------------------------------------------------------------------- /lib/SignLink-1.34.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergerkiller/TrainCarts/HEAD/lib/SignLink-1.34.jar -------------------------------------------------------------------------------- /release/TrainCarts-1.73.1-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergerkiller/TrainCarts/HEAD/release/TrainCarts-1.73.1-SNAPSHOT.jar -------------------------------------------------------------------------------- /lib/bukkit-1.7.2-R0.4-20140216.011848-2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergerkiller/TrainCarts/HEAD/lib/bukkit-1.7.2-R0.4-20140216.011848-2.jar -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionJump.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionJump { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/WaitAction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public interface WaitAction extends MovementAction { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/GroupUnloadedException.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | public class GroupUnloadedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionType.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | public enum SignActionType { 4 | REDSTONE_CHANGE, REDSTONE_ON, REDSTONE_OFF, MEMBER_ENTER, MEMBER_MOVE, MEMBER_LEAVE, GROUP_ENTER, GROUP_LEAVE, 5 | MEMBER_UPDATE, GROUP_UPDATE; 6 | } -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/MemberMissingException.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | /** 4 | * Exception thrown when a member can no longer be accessed 5 | */ 6 | public class MemberMissingException extends RuntimeException { 7 | private static final long serialVersionUID = 1L; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypeDetector.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.Material; 4 | 5 | public class RailTypeDetector extends RailTypeRegular { 6 | 7 | @Override 8 | public boolean isRail(Material type, int data) { 9 | return type == Material.DETECTOR_RAIL; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/BlockAction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.block.Block; 4 | 5 | public class BlockAction extends Action { 6 | private final Block block; 7 | 8 | public BlockAction(Block block) { 9 | this.block = block; 10 | } 11 | 12 | public Block getBlock() { 13 | return this.block; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitForever.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionWaitForever extends GroupAction implements WaitAction { 4 | 5 | @Override 6 | public boolean update() { 7 | getGroup().stop(); 8 | return false; 9 | } 10 | 11 | @Override 12 | public boolean isMovementSuppressed() { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/MinecartPassengerNetwork.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller; 2 | 3 | import com.bergerkiller.bukkit.common.controller.EntityNetworkController; 4 | 5 | /** 6 | * This is needed to fix the annoying passenger exit bugs going on 7 | */ 8 | @SuppressWarnings("rawtypes") 9 | public class MinecartPassengerNetwork extends EntityNetworkController { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionSizzle.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionSizzle extends GroupAction { 4 | 5 | @Override 6 | public void start() { 7 | int j; 8 | for (int i = 0; i < this.getGroup().size(); i++) { 9 | j = i * 3; 10 | if (j < this.getGroup().size()) { 11 | this.getGroup().get(j).playLinkEffect(false); 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/properties/IPropertiesHolder.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.properties; 2 | 3 | public interface IPropertiesHolder extends IParsable { 4 | 5 | /** 6 | * Gets the properties 7 | * 8 | * @return the Properties 9 | */ 10 | public IProperties getProperties(); 11 | 12 | /** 13 | * Called when certain properties have changed 14 | */ 15 | public void onPropertiesChanged(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/properties/IParsable.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.properties; 2 | 3 | public interface IParsable { 4 | /** 5 | * Sets a property denoted by the key by parsing the args specified 6 | * 7 | * @param key of the property (lower-cased and trimmed of surrounding spaces) 8 | * @param value to set to 9 | * @return True if something was set, False if not 10 | */ 11 | public boolean parseSet(String key, String args); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.Event; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | 7 | public abstract class GroupEvent extends Event { 8 | private final MinecartGroup group; 9 | 10 | public GroupEvent(final MinecartGroup group) { 11 | this.group = group; 12 | } 13 | 14 | public MinecartGroup getGroup() { 15 | return this.group; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitTicks.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionWaitTicks extends GroupActionWaitForever { 4 | private int ticks; 5 | 6 | public GroupActionWaitTicks(int ticks) { 7 | this.ticks = ticks; 8 | } 9 | 10 | @Override 11 | public boolean update() { 12 | if (this.ticks <= 0) { 13 | return true; 14 | } else { 15 | this.ticks--; 16 | return super.update(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitDelay.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionWaitDelay extends GroupActionWaitTill implements WaitAction { 4 | private long delay; 5 | 6 | public GroupActionWaitDelay(long delayMS) { 7 | super(System.currentTimeMillis() + delayMS); 8 | this.delay = delayMS; 9 | } 10 | 11 | @Override 12 | public void start() { 13 | this.setTime(System.currentTimeMillis() + delay); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MovementAction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | /** 4 | * Represents an action that controls train movement 5 | */ 6 | public interface MovementAction { 7 | 8 | /** 9 | * Tells the train whether movement control should be suppressed. 10 | * If this action controls velocity/position changes, this should return True. 11 | * 12 | * @return True if movement is suppressed, False if not 13 | */ 14 | public boolean isMovementSuppressed(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/AveragedItemParser.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import com.bergerkiller.bukkit.common.inventory.ItemParser; 4 | 5 | /** 6 | * An ItemParser that distributes items in an averaged way 7 | */ 8 | public class AveragedItemParser extends ItemParser { 9 | 10 | public AveragedItemParser(ItemParser itemParser, int multiplier) { 11 | super(itemParser.getType(), itemParser.hasAmount() ? itemParser.getAmount() * multiplier : multiplier, itemParser.getData()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitTill.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class GroupActionWaitTill extends GroupActionWaitForever { 4 | private long finishtime; 5 | 6 | public GroupActionWaitTill(final long finishtime) { 7 | this.setTime(finishtime); 8 | } 9 | 10 | protected void setTime(long finishtime) { 11 | this.finishtime = finishtime; 12 | } 13 | 14 | @Override 15 | public boolean update() { 16 | return this.finishtime <= System.currentTimeMillis() || super.update(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/BlockActionSetLevers.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.block.Block; 4 | 5 | import com.bergerkiller.bukkit.common.utils.BlockUtil; 6 | 7 | public class BlockActionSetLevers extends BlockAction { 8 | private final boolean down; 9 | 10 | public BlockActionSetLevers(Block block, boolean down) { 11 | super(block); 12 | this.down = down; 13 | } 14 | 15 | @Override 16 | public void start() { 17 | BlockUtil.setLeversAroundBlock(this.getBlock(), this.down); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionWaitDistance.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | public class MemberActionWaitDistance extends MemberAction implements WaitAction { 4 | private double distance; 5 | 6 | public MemberActionWaitDistance(double distance) { 7 | this.distance = distance; 8 | } 9 | 10 | @Override 11 | public boolean update() { 12 | this.distance -= this.getEntity().getMovedXZDistance(); 13 | return this.distance <= 0; 14 | } 15 | 16 | @Override 17 | public boolean isMovementSuppressed() { 18 | return true; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitState.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | /** 4 | * TODO: Used by the blocker sign only, is slightly misnamed, needs proper Blocker class instead 5 | */ 6 | public class GroupActionWaitState extends GroupActionWaitForever { 7 | private boolean stop = false; 8 | 9 | @Override 10 | public boolean update() { 11 | return this.stop || super.update(); 12 | } 13 | 14 | public void stop() { 15 | this.stop = true; 16 | } 17 | 18 | @Override 19 | public boolean isMovementSuppressed() { 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypeActivator.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.Material; 4 | 5 | public class RailTypeActivator extends RailTypeRegular { 6 | private final boolean isPowered; 7 | 8 | protected RailTypeActivator(boolean isPowered) { 9 | this.isPowered = isPowered; 10 | } 11 | 12 | public boolean isPowered() { 13 | return this.isPowered; 14 | } 15 | 16 | @Override 17 | public boolean isRail(Material type, int data) { 18 | return type == Material.ACTIVATOR_RAIL && ((data & 0x8) == 0x8) == isPowered; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/SoftReference.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | public class SoftReference { 4 | 5 | private java.lang.ref.SoftReference ref = null; 6 | 7 | /** 8 | * Gets the value from this reference 9 | * @return the value 10 | */ 11 | public T get() { 12 | return this.ref == null ? null : this.ref.get(); 13 | } 14 | 15 | /** 16 | * Sets the reference to the given value 17 | * @param value 18 | * @return the value 19 | */ 20 | public T set(T value) { 21 | this.ref = value == null ? null : new java.lang.ref.SoftReference(value); 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.Event; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | 8 | public abstract class MemberEvent extends Event { 9 | protected MinecartMember member; 10 | 11 | public MemberEvent(final MinecartMember member) { 12 | this.member = member; 13 | } 14 | 15 | public MinecartMember getMember() { 16 | return this.member; 17 | } 18 | 19 | public MinecartGroup getGroup() { 20 | return this.getMember().getGroup(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/Action.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import com.bergerkiller.bukkit.common.ToggledState; 4 | 5 | public class Action { 6 | private final ToggledState started = new ToggledState(); 7 | 8 | public boolean doTick() { 9 | if (this.started.set()) { 10 | this.start(); 11 | } 12 | return this.update(); 13 | } 14 | 15 | public boolean update() { 16 | return true; 17 | } 18 | 19 | /** 20 | * Called right after this Action is bound to a group or member 21 | */ 22 | public void bind() { 23 | } 24 | 25 | public void start() { 26 | // Default implementation does nothing here 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/MinecartMemberInventory.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller; 2 | 3 | import org.bukkit.inventory.ItemStack; 4 | 5 | import com.bergerkiller.bukkit.common.controller.EntityInventoryController; 6 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartInventory; 7 | 8 | public class MinecartMemberInventory extends EntityInventoryController> { 9 | 10 | @Override 11 | public void onItemSet(int index, ItemStack item) { 12 | super.onItemSet(index, item); 13 | // Mark the Entity as changed 14 | ((MinecartMember) entity.getController()).onPropertiesChanged(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/GroundItemsState.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.inventory.InventoryHolder; 5 | 6 | import com.bergerkiller.bukkit.common.bases.BlockStateBase; 7 | 8 | public class GroundItemsState extends BlockStateBase implements InventoryHolder { 9 | private GroundItemsInventory inventory; 10 | 11 | public GroundItemsState(Block block, int radius) { 12 | super(block); 13 | this.inventory = new GroundItemsInventory(block, (double) radius + 0.5); 14 | } 15 | 16 | @Override 17 | public GroundItemsInventory getInventory() { 18 | return this.inventory; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionRefill.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartFurnace; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 5 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberFurnace; 6 | 7 | public class GroupActionRefill extends GroupAction { 8 | 9 | @Override 10 | public void start() { 11 | for (MinecartMember member : this.getGroup()) { 12 | if (member instanceof MinecartMemberFurnace) { 13 | ((MinecartMemberFurnace) member).getEntity().setFuelTicks(CommonMinecartFurnace.COAL_FUEL); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Train_Carts 2 | main: com.bergerkiller.bukkit.tc.TrainCarts 3 | version: ${project.version} 4 | authors: [bergerkiller, lenis0012, timstans] 5 | description: Plugin that allows the use of minecart trains with adjustable settings 6 | depend: [BKCommonLib] 7 | softdepend: [MinecartManiaCore, SignLink, My Worlds] 8 | metrics: true 9 | dev-url: ${project.url} 10 | commands: 11 | train: 12 | description: Perform TrainCarts commands for complete trains 13 | usage: See development or WIKI page of TrainCarts 14 | cart: 15 | description: Perform TrainCarts commands for single minecarts 16 | usage: See development or WIKI page of TrainCarts -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupAction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.World; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | 7 | public class GroupAction extends Action { 8 | private MinecartGroup group; 9 | 10 | @Override 11 | public boolean doTick() { 12 | if (this.group.isEmpty()) { 13 | return true; 14 | } 15 | return super.doTick(); 16 | } 17 | 18 | public MinecartGroup getGroup() { 19 | return this.group; 20 | } 21 | 22 | public void setGroup(MinecartGroup group) { 23 | this.group = group; 24 | } 25 | 26 | public World getWorld() { 27 | return this.group.getWorld(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/SoundLoop.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import java.util.Random; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 6 | 7 | /** 8 | * Handles the constant playing of sounds in a minecart 9 | */ 10 | public class SoundLoop> { 11 | protected final T member; 12 | protected final Random random = new Random(); 13 | 14 | public SoundLoop(T member) { 15 | this.member = member; 16 | } 17 | 18 | public void play(String soundName, float pitch, float volume) { 19 | this.member.getEntity().makeSound(soundName, volume, pitch); 20 | } 21 | 22 | public void onTick() { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/BlockTimeoutMap.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import org.bukkit.block.Block; 4 | 5 | import com.bergerkiller.bukkit.common.collections.BlockMap; 6 | 7 | /** 8 | * Used to store a simple 'time out' value to a block, 9 | * and quickly find out if this block can be used again. 10 | */ 11 | public class BlockTimeoutMap extends BlockMap { 12 | private static final long serialVersionUID = 1L; 13 | 14 | public void mark(Block block) { 15 | super.put(block, System.currentTimeMillis()); 16 | } 17 | 18 | public boolean isMarked(Block block, final long timeout) { 19 | Long value = super.get(block); 20 | return value != null && value + timeout > System.currentTimeMillis(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/detector/DetectorListener.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.detector; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 5 | 6 | public interface DetectorListener { 7 | public void onRegister(DetectorRegion region); 8 | public void onUnregister(DetectorRegion region); 9 | public void onLeave(final MinecartMember member); 10 | public void onEnter(final MinecartMember member); 11 | public void onLeave(final MinecartGroup group); 12 | public void onEnter(final MinecartGroup group); 13 | public void onUnload(final MinecartGroup group); 14 | public void onUpdate(final MinecartMember member); 15 | public void onUpdate(final MinecartGroup group); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupRemoveEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | 8 | public class GroupRemoveEvent extends GroupEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public GroupRemoveEvent(final MinecartGroup group) { 12 | super(group); 13 | } 14 | 15 | public static void call(final MinecartGroup group) { 16 | CommonUtil.callEvent(new GroupRemoveEvent(group)); 17 | } 18 | 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public static HandlerList getHandlerList() { 24 | return handlers; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupUnloadEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | 8 | public class GroupUnloadEvent extends GroupEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public GroupUnloadEvent(final MinecartGroup group) { 12 | super(group); 13 | } 14 | 15 | public static void call(final MinecartGroup group) { 16 | CommonUtil.callEvent(new GroupUnloadEvent(group)); 17 | } 18 | 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public static HandlerList getHandlerList() { 24 | return handlers; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupCreateEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | 8 | public class GroupCreateEvent extends GroupEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public HandlerList getHandlers() { 12 | return handlers; 13 | } 14 | 15 | public static HandlerList getHandlerList() { 16 | return handlers; 17 | } 18 | 19 | public GroupCreateEvent(final MinecartGroup group) { 20 | super(group); 21 | } 22 | 23 | public static void call(final MinecartGroup group) { 24 | CommonUtil.callEvent(new GroupCreateEvent(group)); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberRemoveEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | 8 | public class MemberRemoveEvent extends MemberEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public MemberRemoveEvent(final MinecartMember member) { 12 | super(member); 13 | } 14 | 15 | public HandlerList getHandlers() { 16 | return handlers; 17 | } 18 | 19 | public static HandlerList getHandlerList() { 20 | return handlers; 21 | } 22 | 23 | public static void call(final MinecartMember member) { 24 | CommonUtil.callEvent(new MemberRemoveEvent(member)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/TrainCartsListener.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.Listener; 4 | 5 | public class TrainCartsListener implements Listener { 6 | public void onCoalUsed(MemberCoalUsedEvent event) {}; 7 | public void onMemberBlockChange(MemberBlockChangeEvent event) {}; 8 | public void onSignAction(SignActionEvent event) {}; 9 | public void onMemberRemove(MemberRemoveEvent event) {}; 10 | public void onGroupForceUpdate(GroupForceUpdateEvent event) {}; 11 | public void onGroupRemove(GroupRemoveEvent event) {}; 12 | public void onGroupCreate(GroupCreateEvent event) {}; 13 | public void onGroupLink(GroupLinkEvent event) {}; 14 | public void onGroupUnload(GroupUnloadEvent event) {}; 15 | public void onMemberAdd(MemberAddEvent event) {}; 16 | } -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | ## Legacy 2 | This is a much older version of Traincarts that is no longer maintained. You can find the up-to-date maintained TeamBergerhealer fork [here](https://github.com/bergerhealer/TrainCarts). 3 | 4 | ## About 5 | This Minecraft Bukkit server plugin links carts together to form trains you can control! 6 | Public transportation redefined. :) 7 | 8 | This old repository hosts a much older version of TrainCarts, suitable for Minecraft/Forge 1.7.10. 9 | TrainCarts uses [BKCommonLib](https://github.com/bergerkiller/BKCommonLib) for a lot of the required functionalities. 10 | 11 | ## Download 12 | BKCommonLib: [v1.59](https://github.com/bergerkiller/BKCommonLib/raw/master/release/BKCommonLib-1.59-SNAPSHOT.jar) 13 | 14 | TrainCarts: [v1.73.1](https://github.com/bergerkiller/TrainCarts/raw/master/release/TrainCarts-1.73.1-SNAPSHOT.jar) 15 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementFuel.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 4 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberFurnace; 5 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 6 | 7 | public class StatementFuel extends Statement { 8 | 9 | @Override 10 | public boolean match(String text) { 11 | return text.equals("coal") || text.equals("fuel") || text.equals("fueled"); 12 | } 13 | 14 | @Override 15 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 16 | return member instanceof MinecartMemberFurnace && ((MinecartMemberFurnace) member).getEntity().hasFuel(); 17 | } 18 | 19 | @Override 20 | public boolean matchArray(String text) { 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementPlayerItems.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | 8 | public class StatementPlayerItems extends StatementItems { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return text.startsWith("playeritems"); 13 | } 14 | 15 | @Override 16 | public boolean matchArray(String text) { 17 | return text.equals("pi"); 18 | } 19 | 20 | @Override 21 | public Inventory getInventory(MinecartMember member) { 22 | return member.getPlayerInventory(); 23 | } 24 | 25 | @Override 26 | public Inventory getInventory(MinecartGroup group) { 27 | return group.getPlayerInventory(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionWaitLocation.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.Location; 4 | 5 | public class MemberActionWaitLocation extends MemberAction implements WaitAction { 6 | private final Location dest; 7 | private final double radiussquared; 8 | 9 | public MemberActionWaitLocation(final Location dest) { 10 | this(dest, 1); 11 | } 12 | 13 | public MemberActionWaitLocation(final Location dest, final double radius) { 14 | this.dest = dest; 15 | this.radiussquared = radius * radius; 16 | } 17 | 18 | @Override 19 | public boolean update() { 20 | if (this.getWorld() != dest.getWorld()) return false; 21 | return this.getEntity().loc.distanceSquared(dest) <= this.radiussquared; 22 | } 23 | 24 | @Override 25 | public boolean isMovementSuppressed() { 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionLaunchDirection.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | public class MemberActionLaunchDirection extends MemberActionLaunch implements MovementAction { 6 | private BlockFace direction; 7 | 8 | public MemberActionLaunchDirection(double targetdistance, double targetvelocity, final BlockFace direction) { 9 | super(targetdistance, targetvelocity); 10 | this.direction = direction; 11 | } 12 | 13 | public void setDirection(BlockFace direction) { 14 | this.direction = direction; 15 | } 16 | 17 | @Override 18 | public boolean update() { 19 | if (super.update()) { 20 | return true; 21 | } 22 | if (super.getDistance() < 1 && this.getMember().isDirectionTo(this.direction.getOppositeFace())) { 23 | this.getGroup().reverse(); 24 | } 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberSpawnEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | 8 | public class MemberSpawnEvent extends MemberEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public MemberSpawnEvent(MinecartMember member) { 12 | super(member); 13 | } 14 | 15 | public void setMember(MinecartMember member) { 16 | this.member = member; 17 | } 18 | 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public static HandlerList getHandlerList() { 24 | return handlers; 25 | } 26 | 27 | public static MemberSpawnEvent call(MinecartMember member) { 28 | return CommonUtil.callEvent(new MemberSpawnEvent(member)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementBoolean.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 5 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 6 | 7 | public class StatementBoolean extends Statement { 8 | 9 | @Override 10 | public boolean match(String text) { 11 | return text.equals("true") || text.equals("false"); 12 | } 13 | 14 | @Override 15 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 16 | return text.equalsIgnoreCase("true"); 17 | } 18 | 19 | @Override 20 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 21 | return text.equalsIgnoreCase("true"); 22 | } 23 | 24 | @Override 25 | public boolean matchArray(String text) { 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementVelocity.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.Util; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 5 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 6 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 7 | 8 | public class StatementVelocity extends Statement { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return text.startsWith("vel") || text.startsWith("speed"); 13 | } 14 | 15 | @Override 16 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 17 | return Util.evaluate(member.getForce(), text); 18 | } 19 | 20 | @Override 21 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 22 | return Util.evaluate(group.getAverageForce(), text); 23 | } 24 | 25 | @Override 26 | public boolean matchArray(String text) { 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberAction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.World; 4 | 5 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | 9 | public class MemberAction extends Action { 10 | private MinecartMember member; 11 | 12 | @Override 13 | public boolean doTick() { 14 | return getEntity().isDead() ? true : super.doTick(); 15 | } 16 | 17 | public MinecartGroup getGroup() { 18 | return this.member.getGroup(); 19 | } 20 | 21 | public MinecartMember getMember() { 22 | return this.member; 23 | } 24 | 25 | public void setMember(MinecartMember member) { 26 | this.member = member; 27 | } 28 | 29 | public CommonMinecart getEntity() { 30 | return this.member.getEntity(); 31 | } 32 | 33 | public World getWorld() { 34 | return getEntity().getWorld(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/ChangingSign.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import org.bukkit.block.Sign; 4 | import org.bukkit.event.block.SignChangeEvent; 5 | 6 | import com.bergerkiller.bukkit.common.bases.BlockStateBase; 7 | 8 | /** 9 | * A sign implementation that ensured proper access to a sign while it is being placed 10 | */ 11 | public class ChangingSign extends BlockStateBase implements Sign { 12 | private final SignChangeEvent event; 13 | 14 | public ChangingSign(SignChangeEvent event) { 15 | super(event.getBlock()); 16 | this.event = event; 17 | } 18 | 19 | @Override 20 | public String getLine(int index) throws IndexOutOfBoundsException { 21 | return this.event.getLine(index); 22 | } 23 | 24 | @Override 25 | public void setLine(int index, String line) throws IndexOutOfBoundsException { 26 | this.event.setLine(index, line); 27 | } 28 | 29 | @Override 30 | public String[] getLines() { 31 | return this.event.getLines(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementTag.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 4 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 5 | 6 | /** 7 | * This tag is a default and always matches, ask it lastly! 8 | */ 9 | public class StatementTag extends Statement { 10 | 11 | @Override 12 | public boolean match(String text) { 13 | return true; 14 | } 15 | 16 | @Override 17 | public boolean matchArray(String text) { 18 | return true; 19 | } 20 | 21 | @Override 22 | public boolean handle(MinecartMember member, String tag, SignActionEvent event) { 23 | return this.handleArray(member, parseArray(tag), event); 24 | } 25 | 26 | @Override 27 | public boolean handleArray(MinecartMember member, String[] tags, SignActionEvent event) { 28 | for (String tag : tags) { 29 | if (member.getProperties().matchTag(tag)) { 30 | return true; 31 | } 32 | } 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementDestination.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 4 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 5 | 6 | public class StatementDestination extends Statement { 7 | 8 | @Override 9 | public boolean match(String text) { 10 | return text.equals("destination"); 11 | } 12 | 13 | @Override 14 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 15 | return member.getProperties().hasDestination(); 16 | } 17 | 18 | @Override 19 | public boolean matchArray(String text) { 20 | return text.equals("d"); 21 | } 22 | 23 | @Override 24 | public boolean handleArray(MinecartMember member, String[] text, SignActionEvent event) { 25 | String dest = member.getProperties().getDestination(); 26 | for (String elem : text) { 27 | if (dest == null ? elem.length() == 0 : elem.equals(dest)) { 28 | return true; 29 | } 30 | } 31 | return false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupForceUpdateEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | 8 | public class GroupForceUpdateEvent extends GroupEvent { 9 | private static final HandlerList handlers = new HandlerList(); 10 | private double force; 11 | 12 | public GroupForceUpdateEvent(final MinecartGroup group, double force) { 13 | super(group); 14 | this.force = force; 15 | } 16 | 17 | public double getForce() { 18 | return this.force; 19 | } 20 | 21 | public void setForce(double value) { 22 | this.force = value; 23 | } 24 | 25 | public static double call(MinecartGroup group, double force) { 26 | return CommonUtil.callEvent(new GroupForceUpdateEvent(group, force)).getForce(); 27 | } 28 | 29 | public HandlerList getHandlers() { 30 | return handlers; 31 | } 32 | 33 | public static HandlerList getHandlerList() { 34 | return handlers; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/SignChangeActionEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.block.SignChangeEvent; 5 | 6 | import com.bergerkiller.bukkit.tc.utils.ChangingSign; 7 | 8 | /** 9 | * A sign action event meant to represent a sign that has just been placed, or has changed
10 | * This ensures that the sign can still properly be interacted with 11 | */ 12 | public class SignChangeActionEvent extends SignActionEvent { 13 | private final SignChangeEvent event; 14 | 15 | public SignChangeActionEvent(SignChangeEvent event) { 16 | super(event.getBlock(), new ChangingSign(event), null); 17 | this.event = event; 18 | } 19 | 20 | /** 21 | * Gets the player that placed this sign 22 | * 23 | * @return Player 24 | */ 25 | public Player getPlayer() { 26 | return this.event.getPlayer(); 27 | } 28 | 29 | @Override 30 | public void setCancelled(boolean cancelled) { 31 | super.setCancelled(cancelled); 32 | this.event.setCancelled(cancelled); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberAddEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | 9 | public class MemberAddEvent extends MemberEvent { 10 | private static final HandlerList handlers = new HandlerList(); 11 | private final MinecartGroup toGroup; 12 | 13 | public MemberAddEvent(final MinecartMember member, final MinecartGroup toGroup) { 14 | super(member); 15 | this.toGroup = toGroup; 16 | } 17 | 18 | public MinecartGroup getTo() { 19 | return this.toGroup; 20 | } 21 | 22 | public HandlerList getHandlers() { 23 | return handlers; 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return handlers; 28 | } 29 | 30 | public static void call(final MinecartMember member, final MinecartGroup toGroup) { 31 | CommonUtil.callEvent(new MemberAddEvent(member, toGroup)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementEmpty.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 5 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberChest; 6 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 7 | 8 | public class StatementEmpty extends Statement { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return text.equals("empty"); 13 | } 14 | 15 | @Override 16 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 17 | return !group.hasItems() && !group.hasPassenger(); 18 | } 19 | 20 | @Override 21 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 22 | if (member instanceof MinecartMemberChest) { 23 | return !((MinecartMemberChest) member).hasItems(); 24 | } 25 | return !member.getEntity().hasPassenger(); 26 | } 27 | 28 | @Override 29 | public boolean matchArray(String text) { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionLaunchLocation.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.BlockFace; 5 | 6 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 7 | 8 | public class MemberActionLaunchLocation extends MemberActionLaunchDirection implements MovementAction { 9 | private final Location target; 10 | 11 | public MemberActionLaunchLocation(double targetvelocity, Location target) { 12 | super(0.0, targetvelocity, BlockFace.SELF); 13 | this.target = target.clone(); 14 | } 15 | 16 | @Override 17 | public void bind() { 18 | super.bind(); 19 | this.setTargetDistance(getMember().getEntity().loc.distance(target)); 20 | this.setDirection(getMember().getDirection()); 21 | } 22 | 23 | @Override 24 | public void start() { 25 | //update direction to launch at 26 | super.setDirection(FaceUtil.getDirection(this.getEntity().getLocation(), this.target, false)); 27 | double d = this.getEntity().loc.xz.distance(this.target); 28 | d += Math.abs(this.target.getBlockY() - this.getEntity().loc.y.block()); 29 | super.setTargetDistance(d); 30 | super.start(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberBlockChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | 9 | public class MemberBlockChangeEvent extends MemberEvent { 10 | private static final HandlerList handlers = new HandlerList(); 11 | private final Block from; 12 | private final Block to; 13 | 14 | private MemberBlockChangeEvent(final MinecartMember member, final Block from, final Block to) { 15 | super(member); 16 | this.from = from; 17 | this.to = to; 18 | } 19 | 20 | public Block getFrom() { 21 | return this.from; 22 | } 23 | 24 | public Block getTo() { 25 | return this.to; 26 | } 27 | 28 | public HandlerList getHandlers() { 29 | return handlers; 30 | } 31 | 32 | public static HandlerList getHandlerList() { 33 | return handlers; 34 | } 35 | 36 | public static void call(final MinecartMember member, final Block from, final Block to) { 37 | CommonUtil.callEvent(new MemberBlockChangeEvent(member, from, to)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementName.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 5 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 6 | import com.bergerkiller.bukkit.tc.properties.TrainProperties; 7 | 8 | public class StatementName extends Statement { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return LogicUtil.contains(text, "renamed", "rename", "ren", "name", "named"); 13 | } 14 | 15 | @Override 16 | public boolean matchArray(String text) { 17 | return text.equals("name") || text.equals("n"); 18 | } 19 | 20 | @Override 21 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 22 | return group.getProperties().isTrainRenamed(); 23 | } 24 | 25 | @Override 26 | public boolean handleArray(MinecartGroup group, String[] text, SignActionEvent event) { 27 | TrainProperties prop = group.getProperties(); 28 | for (String name : text) { 29 | if (prop.getTrainName().equals(name)) { 30 | return true; 31 | } 32 | } 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementDirection.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 6 | import com.bergerkiller.bukkit.tc.Direction; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | 11 | public class StatementDirection extends Statement { 12 | 13 | @Override 14 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 15 | BlockFace[] directions = Direction.parseAll(text, event.getFacing().getOppositeFace()); 16 | return directions.length > 0 && LogicUtil.contains(member.getDirectionFrom(), directions); 17 | } 18 | 19 | @Override 20 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 21 | return handle(group.head(), text, event); 22 | } 23 | 24 | @Override 25 | public boolean match(String text) { 26 | return Direction.parseAll(text).length > 0; 27 | } 28 | 29 | @Override 30 | public boolean matchArray(String text) { 31 | return false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/TCPacketListener.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import com.bergerkiller.bukkit.common.events.PacketReceiveEvent; 6 | import com.bergerkiller.bukkit.common.events.PacketSendEvent; 7 | import com.bergerkiller.bukkit.common.protocol.CommonPacket; 8 | import com.bergerkiller.bukkit.common.protocol.PacketListener; 9 | import com.bergerkiller.bukkit.common.protocol.PacketType; 10 | 11 | /** 12 | * Temporary (???) packet listener to handle and cancel player SHIFT presses to cancel vehicle exit 13 | */ 14 | public class TCPacketListener implements PacketListener { 15 | 16 | @Override 17 | public void onPacketSend(PacketSendEvent event) { 18 | } 19 | 20 | @Override 21 | public void onPacketReceive(PacketReceiveEvent event) { 22 | CommonPacket packet = event.getPacket(); 23 | if (event.getType() == PacketType.IN_STEER_VEHICLE && packet.read(PacketType.IN_STEER_VEHICLE.unmount)) { 24 | // Handle vehicle exit cancelling 25 | Player player = event.getPlayer(); 26 | if (!TrainCarts.handlePlayerVehicleChange(player, null)) { 27 | packet.write(PacketType.IN_STEER_VEHICLE.unmount, false); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementPermission.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 8 | 9 | public class StatementPermission extends Statement { 10 | 11 | @Override 12 | public boolean match(String text) { 13 | return false; 14 | } 15 | 16 | @Override 17 | public boolean matchArray(String text) { 18 | return text.equals("pm") || text.equals("perm"); 19 | } 20 | 21 | @Override 22 | public boolean handleArray(MinecartGroup group, String[] text, SignActionEvent event) { 23 | for (MinecartMember member : group) { 24 | if (!handleArray(member, text, event)) { 25 | return false; 26 | } 27 | } 28 | return true; 29 | } 30 | 31 | @Override 32 | public boolean handleArray(MinecartMember member, String[] text, SignActionEvent event) { 33 | if (member.getEntity().hasPlayerPassenger()) { 34 | Player passenger = member.getEntity().getPlayerPassenger(); 35 | for (String perm : text) { 36 | if (!passenger.hasPermission(perm)) { 37 | return false; 38 | } 39 | } 40 | } 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementOwners.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.Util; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 5 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 6 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 7 | 8 | public class StatementOwners extends Statement { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return text.equals("owner") || text.equals("owners"); 13 | } 14 | 15 | @Override 16 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 17 | return Util.evaluate(member.getProperties().getOwners().size(), text); 18 | } 19 | 20 | @Override 21 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 22 | return Util.evaluate(group.getProperties().getOwners().size(), text); 23 | } 24 | 25 | @Override 26 | public boolean matchArray(String text) { 27 | return text.equals("o"); 28 | } 29 | 30 | @Override 31 | public boolean handleArray(MinecartMember member, String[] owners, SignActionEvent event) { 32 | for (String owner : owners) { 33 | if (member.getProperties().isOwner(owner.toLowerCase())) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/MemberCoalUsedEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.tc.TrainCarts; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | 9 | public class MemberCoalUsedEvent extends MemberEvent { 10 | private static final HandlerList handlers = new HandlerList(); 11 | private boolean useCoal; 12 | private boolean refill; 13 | 14 | public MemberCoalUsedEvent(final MinecartMember source) { 15 | super(source); 16 | this.useCoal = TrainCarts.useCoalFromStorageCart; 17 | this.refill = false; 18 | } 19 | 20 | public boolean useCoal() { 21 | return this.useCoal; 22 | } 23 | 24 | public boolean refill() { 25 | return this.refill; 26 | } 27 | 28 | public void setUseCoal(boolean use) { 29 | this.useCoal = use; 30 | } 31 | 32 | public void setRefill(boolean refill) { 33 | this.refill = refill; 34 | } 35 | 36 | public HandlerList getHandlers() { 37 | return handlers; 38 | } 39 | 40 | public static HandlerList getHandlerList() { 41 | return handlers; 42 | } 43 | 44 | public static MemberCoalUsedEvent call(final MinecartMember member) { 45 | return CommonUtil.callEvent(new MemberCoalUsedEvent(member)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/pathfinding/PathConnection.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.pathfinding; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | 7 | import org.bukkit.block.BlockFace; 8 | 9 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 10 | 11 | public class PathConnection { 12 | public final int distance; 13 | public final BlockFace direction; 14 | public final PathNode destination; 15 | 16 | public PathConnection(PathNode destination, DataInputStream stream) throws IOException { 17 | this.destination = destination; 18 | this.distance = stream.readInt(); 19 | this.direction = FaceUtil.notchToFace((int) stream.readByte() << 1); 20 | } 21 | public PathConnection(PathNode destination, int distance, BlockFace direction) { 22 | this.destination = destination; 23 | this.distance = distance; 24 | this.direction = direction; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "to " + destination.toString() + " going " + this.direction.toString() + " distance " + this.distance; 30 | } 31 | 32 | public void writeTo(DataOutputStream stream) throws IOException { 33 | stream.writeInt(this.destination.index); 34 | stream.writeInt(this.distance); 35 | stream.writeByte(FaceUtil.faceToNotch(this.direction) >> 1); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionTrigger.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import com.bergerkiller.bukkit.tc.ArrivalSigns; 4 | import com.bergerkiller.bukkit.tc.Permission; 5 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 6 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 7 | 8 | public class SignActionTrigger extends SignAction { 9 | 10 | @Override 11 | public boolean match(SignActionEvent info) { 12 | return info.isType("trigger"); 13 | } 14 | 15 | @Override 16 | public void execute(SignActionEvent info) { 17 | if (info.isAction(SignActionType.REDSTONE_ON, SignActionType.GROUP_ENTER, SignActionType.REDSTONE_OFF)) { 18 | if (info.isTrainSign() || info.isCartSign()) { 19 | if (info.isPowered()) { 20 | ArrivalSigns.trigger(info.getSign(), info.getMember()); 21 | } else if (info.isAction(SignActionType.REDSTONE_OFF)) { 22 | ArrivalSigns.timeCalcStop(info.getBlock()); 23 | } 24 | } 25 | } 26 | } 27 | 28 | @Override 29 | public boolean build(SignChangeActionEvent event) { 30 | if (event.getMode() != SignActionMode.NONE) { 31 | return handleBuild(event, Permission.BUILD_TRIGGER, "train trigger", "reset the arrival time, train name and destination, which can be displayed using SignLink"); 32 | } 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/PoweredCartSoundLoop.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import com.bergerkiller.bukkit.common.collections.InterpolatedMap; 4 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberFurnace; 5 | 6 | /** 7 | * Keeps track of the current sound to 8 | */ 9 | public class PoweredCartSoundLoop extends SoundLoop { 10 | private static InterpolatedMap nodes = new InterpolatedMap(); 11 | private int swooshSoundCounter = 0; 12 | 13 | static { 14 | nodes.put(0.0, Integer.MAX_VALUE); 15 | nodes.put(0.001, 50.0); 16 | nodes.put(0.005, 23.0); 17 | nodes.put(0.01, 18.0); 18 | nodes.put(0.05, 16.0); 19 | nodes.put(0.1, 14.0); 20 | nodes.put(0.2, 8.0); 21 | nodes.put(0.4, 5.0); 22 | } 23 | 24 | public PoweredCartSoundLoop(MinecartMemberFurnace member) { 25 | super(member); 26 | } 27 | 28 | @Override 29 | public void onTick() { 30 | if (!member.getEntity().hasFuel()) { 31 | return; 32 | } 33 | this.swooshSoundCounter++; 34 | int interval = (int) nodes.get(member.getEntity().getMovedDistance()); 35 | if (this.swooshSoundCounter >= interval) { 36 | this.swooshSoundCounter = 0; 37 | play("step.cloth", 0.4f + 0.2f * random.nextFloat(), 0.8f); 38 | play("random.fizz", 1.5f + 0.3f * random.nextFloat(), 0.05f + 0.1f * random.nextFloat()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionMode.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.Sign; 4 | import org.bukkit.event.block.SignChangeEvent; 5 | 6 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 7 | 8 | public enum SignActionMode { 9 | TRAIN, CART, RCTRAIN, NONE; 10 | 11 | public static SignActionMode fromString(String name) { 12 | if (name.endsWith("]") && name.startsWith("[")) { 13 | name = name.substring(1, name.length() - 1); 14 | if (name.startsWith("!") || name.startsWith("+")) { 15 | name = name.substring(1); 16 | } 17 | name = name.toLowerCase(); 18 | // further parsing 19 | if (name.startsWith("train ") && name.length() > 6) { 20 | return RCTRAIN; 21 | } else if (name.startsWith("t ") && name.length() > 2) { 22 | return RCTRAIN; 23 | } else if (name.startsWith("train")) { 24 | return TRAIN; 25 | } else if (name.startsWith("cart")) { 26 | return CART; 27 | } 28 | } 29 | return NONE; 30 | } 31 | 32 | public static SignActionMode fromSign(Sign sign) { 33 | return sign == null ? NONE : fromString(sign.getLine(0)); 34 | } 35 | 36 | public static SignActionMode fromEvent(SignActionEvent event) { 37 | return fromSign(event.getSign()); 38 | } 39 | 40 | public static SignActionMode fromEvent(SignChangeEvent event) { 41 | return fromString(event.getLine(0)); 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/type/MinecartMemberHopper.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.type; 2 | 3 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartHopper; 4 | import com.bergerkiller.bukkit.tc.GroupUnloadedException; 5 | import com.bergerkiller.bukkit.tc.MemberMissingException; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMemberInventory; 8 | 9 | public class MinecartMemberHopper extends MinecartMember { 10 | 11 | @Override 12 | public void onAttached() { 13 | super.onAttached(); 14 | entity.setInventoryController(new MinecartMemberInventory()); 15 | } 16 | 17 | @Override 18 | public void onActivatorUpdate(boolean activated) { 19 | if (entity.isSuckingItems() != activated) { 20 | entity.setSuckingItems(activated); 21 | } 22 | } 23 | 24 | @Override 25 | public void onPhysicsPostMove(double speedFactor) throws MemberMissingException, GroupUnloadedException { 26 | super.onPhysicsPostMove(speedFactor); 27 | if (entity.isDead() || !entity.isSuckingItems()) { 28 | return; 29 | } 30 | entity.setSuckingCooldown(entity.getSuckingCooldown() - 1); 31 | if (entity.getSuckingCooldown() <= 0) { 32 | entity.setSuckingCooldown(0); 33 | if (entity.suckItems()) { 34 | entity.setSuckingCooldown(4); 35 | entity.update(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/logic/RailLogicGround.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.logic; 2 | 3 | import org.bukkit.block.BlockFace; 4 | import org.bukkit.util.Vector; 5 | 6 | import com.bergerkiller.bukkit.common.bases.IntVector3; 7 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 8 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | 11 | /** 12 | * Handles the rail logic of a minecart sliding on the ground 13 | */ 14 | public class RailLogicGround extends RailLogic { 15 | public static final RailLogicGround INSTANCE = new RailLogicGround(); 16 | 17 | private RailLogicGround() { 18 | super(BlockFace.SELF); 19 | } 20 | 21 | @Override 22 | public BlockFace getMovementDirection(MinecartMember member, Vector movement) { 23 | return FaceUtil.getDirection(movement); 24 | } 25 | 26 | @Override 27 | public boolean hasVerticalMovement() { 28 | return true; 29 | } 30 | 31 | @Override 32 | public Vector getFixedPosition(CommonMinecart entity, double x, double y, double z, IntVector3 railPos) { 33 | return new Vector(x, y, z); 34 | } 35 | 36 | @Override 37 | public void onPreMove(MinecartMember member) { 38 | // Apply ground friction 39 | if (!member.isMovementControlled()) { 40 | member.getEntity().vel.multiply(member.getEntity().getDerailedVelocityMod()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/events/GroupLinkEvent.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.events; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 9 | 10 | public class GroupLinkEvent extends Event implements Cancellable { 11 | private static final HandlerList handlers = new HandlerList(); 12 | private final MinecartGroup group1; 13 | private final MinecartGroup group2; 14 | private boolean cancelled = false; 15 | 16 | public GroupLinkEvent(final MinecartGroup group1, final MinecartGroup group2) { 17 | this.group1 = group1; 18 | this.group2 = group2; 19 | } 20 | 21 | public MinecartGroup getGroup1() { 22 | return this.group1; 23 | } 24 | 25 | public MinecartGroup getGroup2() { 26 | return this.group2; 27 | } 28 | 29 | @Override 30 | public boolean isCancelled() { 31 | return this.cancelled; 32 | } 33 | 34 | @Override 35 | public void setCancelled(boolean cancel) { 36 | this.cancelled = cancel; 37 | } 38 | 39 | public HandlerList getHandlers() { 40 | return handlers; 41 | } 42 | 43 | public static HandlerList getHandlerList() { 44 | return handlers; 45 | } 46 | 47 | public static GroupLinkEvent call(final MinecartGroup group1, final MinecartGroup group2) { 48 | return CommonUtil.callEvent(new GroupLinkEvent(group1, group2)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementRandom.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.common.utils.MathUtil; 4 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 8 | 9 | public class StatementRandom extends Statement { 10 | 11 | @Override 12 | public boolean match(String text) { 13 | return text.startsWith("rand"); 14 | } 15 | 16 | @Override 17 | public boolean matchArray(String text) { 18 | return text.startsWith("rand"); 19 | } 20 | 21 | private boolean handle(String... text) { 22 | double chance = 0.5; 23 | if (text.length > 0) { 24 | chance = ParseUtil.parseDouble(text[0], chance); 25 | if (text[0].endsWith("%")) { 26 | chance /= 100; 27 | } 28 | chance = MathUtil.clamp(chance, 0.0, 1.0); 29 | } 30 | return Math.random() <= chance; 31 | } 32 | 33 | @Override 34 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 35 | return handle(); 36 | } 37 | 38 | @Override 39 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 40 | return handle(); 41 | } 42 | 43 | @Override 44 | public boolean handleArray(MinecartGroup group, String[] text, SignActionEvent event) { 45 | return handle(text); 46 | } 47 | 48 | @Override 49 | public boolean handleArray(MinecartMember member, String[] text, SignActionEvent event) { 50 | return handle(text); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/ChunkArea.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import com.bergerkiller.bukkit.common.bases.IntVector2; 4 | 5 | /** 6 | * Stores the chunk coordinates and a 5x5 chunk area around it 7 | */ 8 | public class ChunkArea { 9 | public static final int CHUNK_RANGE = 2; 10 | public static final int CHUNK_EDGE = 2 * CHUNK_RANGE + 1; 11 | public static final int CHUNK_AREA = CHUNK_EDGE * CHUNK_EDGE; 12 | private int x, z; 13 | private final IntVector2[] chunks = new IntVector2[CHUNK_AREA]; 14 | 15 | public ChunkArea(ChunkArea area) { 16 | this.x = area.x; 17 | this.z = area.z; 18 | System.arraycopy(area.chunks, 0, this.chunks, 0, CHUNK_AREA); 19 | } 20 | 21 | public ChunkArea(int x, int z) { 22 | updateForced(x, z); 23 | } 24 | 25 | public int getX() { 26 | return x; 27 | } 28 | 29 | public int getZ() { 30 | return z; 31 | } 32 | 33 | public IntVector2[] getChunks() { 34 | return chunks; 35 | } 36 | 37 | public void update(ChunkArea area) { 38 | if (this.x != area.x || this.z != area.z) { 39 | this.x = area.x; 40 | this.z = area.z; 41 | System.arraycopy(area.chunks, 0, this.chunks, 0, CHUNK_AREA); 42 | } 43 | } 44 | 45 | public void update(int x, int z) { 46 | if (this.x != x || this.z != z) { 47 | updateForced(x, z); 48 | } 49 | } 50 | 51 | private void updateForced(int x, int z) { 52 | this.x = x; 53 | this.z = z; 54 | int cx, cz; 55 | int i = 0; 56 | for (cx = -CHUNK_RANGE; cx <= CHUNK_RANGE; cx++) { 57 | for (cz = -CHUNK_RANGE; cz <= CHUNK_RANGE; cz++) { 58 | chunks[i++] = new IntVector2(x + cx, z + cz); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/logic/RailLogicVerticalSlopeUp.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.logic; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 6 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | 9 | /** 10 | * Handles the rail logic for a vertical rail to sloped rail
11 | * This is a stub: This should eventually replace the teleport logic in the Minecart members' move info 12 | */ 13 | public class RailLogicVerticalSlopeUp extends RailLogicHorizontal { 14 | private static final RailLogicVerticalSlopeUp[] values = new RailLogicVerticalSlopeUp[4]; 15 | static { 16 | for (int i = 0; i < 4; i++) { 17 | values[i] = new RailLogicVerticalSlopeUp(FaceUtil.notchToFace(i << 1)); 18 | } 19 | } 20 | 21 | protected RailLogicVerticalSlopeUp(BlockFace direction) { 22 | super(direction); 23 | } 24 | 25 | @Override 26 | public boolean isSloped() { 27 | return true; 28 | } 29 | 30 | @Override 31 | public void onPreMove(MinecartMember member) { 32 | final CommonMinecart entity = member.getEntity(); 33 | entity.vel.xz.add(this.getDirection(), entity.vel.getY()); 34 | entity.vel.y.setZero(); 35 | super.onPreMove(member); 36 | } 37 | 38 | /** 39 | * Gets the sloped-vertical rail logic for the the vertical track leading horizontal facing the direction specified 40 | * 41 | * @param direction of the sloped rail 42 | * @return Rail Logic 43 | */ 44 | public static RailLogicVerticalSlopeUp get(BlockFace direction) { 45 | return values[FaceUtil.faceToNotch(direction) >> 1]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementType.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import java.util.Locale; 4 | 5 | import org.bukkit.entity.EntityType; 6 | 7 | import com.bergerkiller.bukkit.common.conversion.Conversion; 8 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 9 | import com.bergerkiller.bukkit.tc.Util; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 13 | 14 | public class StatementType extends Statement { 15 | 16 | private boolean isSize(String text) { 17 | return LogicUtil.contains(text, "cartcount", "trainsize", "length", "count", "size"); 18 | } 19 | 20 | @Override 21 | public boolean match(String text) { 22 | return isSize(text) || Conversion.toMinecartType.convert(text) != null; 23 | } 24 | 25 | @Override 26 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 27 | if (isSize(text.toLowerCase(Locale.ENGLISH))) { 28 | return true; 29 | } 30 | return member.getEntity().getType() == Conversion.toMinecartType.convert(text); 31 | } 32 | 33 | @Override 34 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 35 | if (isSize(text.toLowerCase(Locale.ENGLISH))) { 36 | return Util.evaluate(group.size(), text); 37 | } 38 | final EntityType type = Conversion.toMinecartType.convert(text); 39 | if (type == null) { 40 | return false; 41 | } else { 42 | return Util.evaluate(group.size(type), text); 43 | } 44 | } 45 | 46 | @Override 47 | public boolean matchArray(String text) { 48 | return false; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementPassenger.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.tc.Util; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 5 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 6 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 7 | 8 | public class StatementPassenger extends Statement { 9 | 10 | @Override 11 | public boolean match(String text) { 12 | return text.startsWith("passenger") || text.startsWith("player"); 13 | } 14 | 15 | @Override 16 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 17 | return text.toLowerCase().startsWith("player") ? member.getEntity().hasPlayerPassenger() : member.getEntity().hasPassenger(); 18 | } 19 | 20 | @Override 21 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 22 | int count = 0; 23 | boolean playermode = text.toLowerCase().startsWith("player"); 24 | for (MinecartMember member : group) { 25 | if (playermode ? member.getEntity().hasPlayerPassenger() : member.getEntity().hasPassenger()) { 26 | count++; 27 | } 28 | } 29 | return Util.evaluate(count, text); 30 | } 31 | 32 | @Override 33 | public boolean matchArray(String text) { 34 | return text.equals("p"); 35 | } 36 | 37 | @Override 38 | public boolean handleArray(MinecartMember member, String[] names, SignActionEvent event) { 39 | if (member.getEntity().hasPlayerPassenger()) { 40 | String pname = member.getEntity().getPlayerPassenger().getName(); 41 | for (String name : names) { 42 | if (Util.matchText(pname, name)) { 43 | return true; 44 | } 45 | } 46 | } 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementPlayerHand.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import java.util.ArrayList; 4 | 5 | import org.bukkit.inventory.Inventory; 6 | import org.bukkit.inventory.ItemStack; 7 | 8 | import com.bergerkiller.bukkit.common.inventory.InventoryBaseImpl; 9 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | 13 | public class StatementPlayerHand extends StatementItems { 14 | 15 | @Override 16 | public boolean match(String text) { 17 | return text.startsWith("playerhand"); 18 | } 19 | 20 | @Override 21 | public boolean matchArray(String text) { 22 | return text.equals("ph"); 23 | } 24 | 25 | @Override 26 | public Inventory getInventory(MinecartMember member) { 27 | ItemStack item = null; 28 | if (member.getEntity().hasPlayerPassenger()) { 29 | item = member.getPlayerInventory().getItemInHand(); 30 | } 31 | if (LogicUtil.nullOrEmpty(item)) { 32 | return new InventoryBaseImpl(new org.bukkit.inventory.ItemStack[0]); 33 | } else { 34 | return new InventoryBaseImpl(new org.bukkit.inventory.ItemStack[] {item}); 35 | } 36 | } 37 | 38 | @Override 39 | public Inventory getInventory(MinecartGroup group) { 40 | ArrayList items = new ArrayList(); 41 | for (MinecartMember member : group) { 42 | if (member.getEntity().hasPlayerPassenger()) { 43 | ItemStack item = member.getPlayerInventory().getItemInHand(); 44 | if (!LogicUtil.nullOrEmpty(item)) { 45 | items.add(item); 46 | } 47 | } 48 | } 49 | return new InventoryBaseImpl(items, false); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementRedstone.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.tc.Direction; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 9 | 10 | public class StatementRedstone extends Statement { 11 | 12 | @Override 13 | public boolean match(String text) { 14 | return text.equals("redstone"); 15 | } 16 | 17 | @Override 18 | public boolean matchArray(String text) { 19 | return text.equals("rs") || text.equals("redstone"); 20 | } 21 | 22 | @Override 23 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 24 | return this.handle(text, event); 25 | } 26 | 27 | @Override 28 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 29 | return this.handle(text, event); 30 | } 31 | 32 | @Override 33 | public boolean handleArray(MinecartMember member, String[] names, SignActionEvent event) { 34 | return this.handle(names, event); 35 | } 36 | 37 | @Override 38 | public boolean handleArray(MinecartGroup group, String[] names, SignActionEvent event) { 39 | return this.handle(names, event); 40 | } 41 | 42 | public boolean handle(String text, SignActionEvent event) { 43 | return event.isPoweredRaw(false); 44 | } 45 | 46 | public boolean handle(String[] names, SignActionEvent event) { 47 | for (String name : names) { 48 | BlockFace direction = Direction.parse(name).getDirection(event.getFacing()); 49 | if (event.getPower(direction).hasPower()) { 50 | return true; 51 | } 52 | } 53 | return false; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionDestroy.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import com.bergerkiller.bukkit.tc.Permission; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 5 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 6 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 7 | 8 | public class SignActionDestroy extends SignAction { 9 | 10 | @Override 11 | public boolean match(SignActionEvent info) { 12 | return info.isType("destroy"); 13 | } 14 | 15 | @Override 16 | public void execute(SignActionEvent info) { 17 | if (!info.isPowered()) return; 18 | if (info.isTrainSign() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.GROUP_ENTER) && info.hasGroup()) { 19 | info.getGroup().playLinkEffect(); 20 | info.getGroup().destroy(); 21 | } else if (info.isCartSign() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.MEMBER_ENTER) && info.hasMember()) { 22 | info.getMember().onDie(); 23 | } else if (info.isRCSign() && info.isAction(SignActionType.REDSTONE_ON)) { 24 | for (MinecartGroup group : info.getRCTrainGroups()) { 25 | group.playLinkEffect(); 26 | group.destroy(); 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | public boolean build(SignChangeActionEvent event) { 33 | if (event.isCartSign()) { 34 | return handleBuild(event, Permission.BUILD_DESTRUCTOR, "cart destructor", "destroy minecarts"); 35 | } else if (event.isTrainSign()) { 36 | return handleBuild(event, Permission.BUILD_DESTRUCTOR, "train destructor", "destroy an entire train"); 37 | } else if (event.isRCSign()) { 38 | return handleBuild(event, Permission.BUILD_DESTRUCTOR, "train destructor", "destroy an entire train remotely"); 39 | } 40 | return false; 41 | } 42 | 43 | @Override 44 | public boolean canSupportRC() { 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypeNone.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.World; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.common.bases.IntVector3; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | import com.bergerkiller.bukkit.tc.rails.logic.RailLogic; 10 | import com.bergerkiller.bukkit.tc.rails.logic.RailLogicAir; 11 | import com.bergerkiller.bukkit.tc.rails.logic.RailLogicGround; 12 | 13 | public class RailTypeNone extends RailType { 14 | 15 | /** 16 | * None never matches - it is returned when no other rail type is found 17 | */ 18 | @Override 19 | public boolean isRail(int typeId, int data) { 20 | return false; 21 | } 22 | 23 | @Override 24 | public IntVector3 findRail(MinecartMember member, World world, IntVector3 pos) { 25 | return pos; 26 | } 27 | 28 | @Override 29 | public Block findMinecartPos(Block trackBlock) { 30 | return trackBlock; 31 | } 32 | 33 | @Override 34 | public BlockFace[] getPossibleDirections(Block trackBlock) { 35 | return new BlockFace[0]; 36 | } 37 | 38 | @Override 39 | public Block findRail(Block pos) { 40 | return pos; 41 | } 42 | 43 | @Override 44 | public Block getNextPos(Block currentTrack, BlockFace currentDirection) { 45 | return null; 46 | } 47 | 48 | @Override 49 | public BlockFace getDirection(Block railsBlock) { 50 | return BlockFace.SELF; 51 | } 52 | 53 | @Override 54 | public BlockFace getSignColumnDirection(Block railsBlock) { 55 | return BlockFace.SELF; 56 | } 57 | 58 | @Override 59 | public RailLogic getLogic(MinecartMember member, Block railsBlock) { 60 | // Two no-rail logic types 61 | if (member.isFlying()) { 62 | return RailLogicAir.INSTANCE; 63 | } else { 64 | return RailLogicGround.INSTANCE; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionWait.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 6 | import com.bergerkiller.bukkit.tc.Permission; 7 | import com.bergerkiller.bukkit.tc.TrainCarts; 8 | import com.bergerkiller.bukkit.tc.actions.MemberActionWaitOccupied; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 11 | 12 | public class SignActionWait extends SignAction { 13 | 14 | @Override 15 | public boolean match(SignActionEvent info) { 16 | return info.isType("wait"); 17 | } 18 | 19 | @Override 20 | public void execute(SignActionEvent info) { 21 | if (info.isAction(SignActionType.GROUP_ENTER) && info.isPowered()) { 22 | if (!info.hasRailedMember()) return; 23 | int dist = Math.min(ParseUtil.parseInt(info.getLine(1), 100), TrainCarts.maxDetectorLength); 24 | long delay = ParseUtil.parseTime(info.getLine(2)); 25 | double launchDistance = ParseUtil.parseDouble(info.getLine(3), 2.0); 26 | 27 | //allowed? 28 | BlockFace dir = info.getMember().getDirectionTo(); 29 | 30 | //distance 31 | if (MemberActionWaitOccupied.handleOccupied(info.getRails(), dir, info.getMember(), dist)) { 32 | info.getGroup().getActions().clear(); 33 | info.getMember().getActions().addActionWaitOccupied(dist, delay, launchDistance); 34 | } 35 | } else if (info.isAction(SignActionType.REDSTONE_OFF)) { 36 | if (!info.hasRailedMember()) return; 37 | info.getGroup().getActions().clear(); 38 | } 39 | } 40 | 41 | @Override 42 | public boolean build(SignChangeActionEvent event) { 43 | if (event.getMode() != SignActionMode.NONE) { 44 | return handleBuild(event, Permission.BUILD_WAIT, "train waiter sign", "waits the train until the tracks ahead are clear"); 45 | } 46 | return false; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/GroupActionWaitPathFinding.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import java.util.HashSet; 4 | 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.entity.Player; 7 | 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | import com.bergerkiller.bukkit.tc.pathfinding.PathConnection; 11 | import com.bergerkiller.bukkit.tc.pathfinding.PathNode; 12 | import com.bergerkiller.bukkit.tc.pathfinding.PathProvider; 13 | 14 | public class GroupActionWaitPathFinding extends GroupActionWaitForever { 15 | private int failCounter = 0; 16 | private final SignActionEvent info; 17 | private final PathNode from; 18 | private final String destination; 19 | 20 | public GroupActionWaitPathFinding(SignActionEvent info, PathNode from, String destination) { 21 | this.info = info; 22 | this.from = from; 23 | this.destination = destination; 24 | } 25 | 26 | @Override 27 | public boolean update() { 28 | if (PathProvider.isProcessing()) { 29 | if (this.failCounter++ == 20) { 30 | HashSet receivers = new HashSet(); 31 | for (MinecartMember member : this.getGroup()) { 32 | // Editing 33 | receivers.addAll(member.getProperties().getEditingPlayers()); 34 | // Occupants 35 | if (member.getEntity().hasPlayerPassenger()) { 36 | receivers.add(member.getEntity().getPlayerPassenger()); 37 | } 38 | } 39 | for (Player player : receivers) { 40 | player.sendMessage(ChatColor.YELLOW + "Looking for a way to reach the destination..."); 41 | } 42 | } 43 | return super.update(); 44 | } else { 45 | // Switch the rails to the right direction 46 | PathConnection conn = this.from.findConnection(this.destination); 47 | if (conn != null) { 48 | this.info.setRailsTo(conn.direction); 49 | } 50 | return true; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/type/MinecartMemberRideable.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.type; 2 | 3 | import org.bukkit.entity.Entity; 4 | 5 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartRideable; 6 | import com.bergerkiller.bukkit.tc.GroupUnloadedException; 7 | import com.bergerkiller.bukkit.tc.MemberMissingException; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | 10 | public class MinecartMemberRideable extends MinecartMember { 11 | private Entity oldPassenger; 12 | 13 | @Override 14 | public void onAttached() { 15 | super.onAttached(); 16 | oldPassenger = entity.getPassenger(); 17 | } 18 | 19 | @Override 20 | public void onPhysicsPostMove(double speedFactor) throws MemberMissingException, GroupUnloadedException { 21 | super.onPhysicsPostMove(speedFactor); 22 | Entity currentPassenger = entity.getPassenger(); 23 | if (oldPassenger != currentPassenger) { 24 | // This was a temporary hotfix for the passengers teleporting out of minecarts all the time 25 | // This bug is now fixed, and thus this hotfix is no longer needed 26 | // In case of re-occurance, uncomment this piece of code 27 | // Note: this DOES cause plugins like Lift and LaunchMe to fail! (they replace network controllers too) 28 | /* 29 | if (currentPassenger != null) { 30 | CommonEntity entity = CommonEntity.get(currentPassenger); 31 | if (!(entity.getNetworkController() instanceof MinecartPassengerNetwork)) { 32 | entity.setNetworkController(new MinecartPassengerNetwork()); 33 | } 34 | } else if (oldPassenger != null) { 35 | CommonEntity entity = CommonEntity.get(oldPassenger); 36 | if (entity.getNetworkController() instanceof MinecartPassengerNetwork) { 37 | entity.setNetworkController(new DefaultEntityNetworkController()); 38 | } 39 | } 40 | */ 41 | oldPassenger = currentPassenger; 42 | this.onPropertiesChanged(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypeCrossing.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 8 | import com.bergerkiller.bukkit.common.utils.MaterialUtil; 9 | import com.bergerkiller.bukkit.tc.Util; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | import com.bergerkiller.bukkit.tc.rails.logic.RailLogic; 12 | import com.bergerkiller.bukkit.tc.rails.logic.RailLogicHorizontal; 13 | 14 | public class RailTypeCrossing extends RailTypeHorizontal { 15 | 16 | @Override 17 | public boolean isRail(Material type, int data) { 18 | return MaterialUtil.ISPRESSUREPLATE.get(type); 19 | } 20 | 21 | @Override 22 | public BlockFace[] getPossibleDirections(Block trackBlock) { 23 | BlockFace dir = getDirection(trackBlock); 24 | if (dir == BlockFace.SELF) { 25 | return FaceUtil.RADIAL; 26 | } else { 27 | return RailTypeRegular.getPossibleDirections(dir); 28 | } 29 | } 30 | 31 | @Override 32 | public Block getNextPos(Block currentTrack, BlockFace currentDirection) { 33 | return currentTrack.getRelative(currentDirection); 34 | } 35 | 36 | @Override 37 | public BlockFace getDirection(Block railsBlock) { 38 | return Util.getPlateDirection(railsBlock); 39 | } 40 | 41 | @Override 42 | public RailLogic getLogic(MinecartMember member, Block railsBlock) { 43 | // Get the direction of the rails to find out the logic to use 44 | BlockFace dir = Util.getPlateDirection(railsBlock); 45 | if (dir == BlockFace.SELF) { 46 | //set track direction based on direction of this cart 47 | dir = FaceUtil.toRailsDirection(member.getDirectionTo()); 48 | } 49 | return RailLogicHorizontal.get(dir); 50 | } 51 | 52 | @Override 53 | public void onPostMove(MinecartMember member) { 54 | super.onPostMove(member); 55 | member.getEntity().loc.y.add(0.17); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/itemanimation/VirtualItem.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.itemanimation; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.EntityType; 5 | import org.bukkit.inventory.ItemStack; 6 | import org.bukkit.util.Vector; 7 | 8 | import com.bergerkiller.bukkit.common.controller.DefaultEntityNetworkController; 9 | import com.bergerkiller.bukkit.common.entity.CommonEntity; 10 | import com.bergerkiller.bukkit.common.entity.type.CommonItem; 11 | import com.bergerkiller.bukkit.common.utils.MathUtil; 12 | 13 | /** 14 | * A dummy Item class that basically does nothing :) 15 | */ 16 | public class VirtualItem { 17 | public final CommonItem item; 18 | private final ItemStack itemStack; 19 | 20 | public VirtualItem(Location location, ItemStack itemstack) { 21 | item = (CommonItem) CommonEntity.create(EntityType.DROPPED_ITEM); 22 | item.last.set(this.item.loc.set(location)); 23 | item.vel.y.add(0.1); 24 | item.setItemStack(itemstack); 25 | itemStack = itemstack; 26 | refresh(); 27 | item.setNetworkController(new DefaultEntityNetworkController()); 28 | } 29 | 30 | public void update(Vector dir) { 31 | // Update velocity 32 | item.vel.setX(dir.getX() + Math.random() * 0.02 - 0.01); 33 | item.vel.setY(MathUtil.useOld(item.vel.getY(), dir.getY(), 0.1)); 34 | item.vel.setZ(dir.getZ() + Math.random() * 0.02 - 0.01); 35 | // Update position using motion 36 | item.last.set(item.loc); 37 | item.loc.add(item.vel); 38 | refresh(); 39 | } 40 | 41 | public void refresh() { 42 | item.setPositionChanged(true); 43 | item.setVelocityChanged(true); 44 | item.setChunkX(item.loc.x.chunk()); 45 | item.setChunkY(item.loc.y.chunk()); 46 | item.setChunkZ(item.loc.z.chunk()); 47 | } 48 | 49 | public void die() { 50 | item.remove(); 51 | item.setNetworkController(null); 52 | } 53 | 54 | public ItemStack getItemStack() { 55 | return itemStack; 56 | } 57 | 58 | public Location getLocation() { 59 | return item.getLocation(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/type/MinecartMemberMobSpawner.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.type; 2 | 3 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartMobSpawner; 4 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 5 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 6 | import com.bergerkiller.bukkit.common.wrappers.MobSpawner; 7 | import com.bergerkiller.bukkit.tc.GroupUnloadedException; 8 | import com.bergerkiller.bukkit.tc.MemberMissingException; 9 | import com.bergerkiller.bukkit.tc.Util; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | 12 | public class MinecartMemberMobSpawner extends MinecartMember { 13 | 14 | @Override 15 | public void onPhysicsPostMove(double speedFactor) throws MemberMissingException, GroupUnloadedException { 16 | super.onPhysicsPostMove(speedFactor); 17 | getEntity().getMobSpawner().onTick(); 18 | } 19 | 20 | /** 21 | * Gets the mob spawner that is used by this Mob Spawner Minecart to spawn mobs at an interval 22 | * 23 | * @return mob spawner 24 | */ 25 | public MobSpawner getSpawner() { 26 | return getEntity().getMobSpawner(); 27 | } 28 | 29 | @Override 30 | public boolean parseSet(String key, String args) { 31 | if (super.parseSet(key, args)) { 32 | return true; 33 | } 34 | if (LogicUtil.contains(key, "mobtype")) { 35 | if (Util.isValidEntity(args)) { 36 | getSpawner().setMobName(args); 37 | } 38 | } else if (LogicUtil.contains(key, "delay", "minspawndelay")) { 39 | getSpawner().setSpawnDelay(ParseUtil.parseInt(args, getSpawner().getSpawnDelay())); 40 | } else if (LogicUtil.contains(key, "mindelay", "minspawndelay")) { 41 | getSpawner().setMinSpawnDelay(ParseUtil.parseInt(args, getSpawner().getMinSpawnDelay())); 42 | } else if (LogicUtil.contains(key, "maxdelay", "maxspawndelay")) { 43 | getSpawner().setMaxSpawnDelay(ParseUtil.parseInt(args, getSpawner().getMaxSpawnDelay())); 44 | } else { 45 | return false; 46 | } 47 | return true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/DirectionStatement.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | import java.util.Locale; 4 | 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 11 | import com.bergerkiller.bukkit.tc.statements.Statement; 12 | 13 | public class DirectionStatement { 14 | public Direction direction; 15 | public String text; 16 | public Integer number; 17 | 18 | public DirectionStatement(String text, BlockFace cartDirection) { 19 | this(text, BlockFace.SELF, Direction.NONE); 20 | } 21 | 22 | public DirectionStatement(String text, BlockFace cartDirection, Direction alternative) { 23 | int idx = text.indexOf(':'); 24 | if (idx == -1) { 25 | this.text = text; 26 | this.direction = alternative; 27 | } else { 28 | this.text = text.substring(idx + 1); 29 | // Parse Direction from String text 30 | final String dirText = text.substring(0, idx).toLowerCase(Locale.ENGLISH); 31 | if (LogicUtil.contains(dirText, "c", "continue")) { 32 | this.direction = Direction.fromFace(cartDirection); 33 | } else if (LogicUtil.contains(dirText, "i", "rev", "reverse", "inverse")) { 34 | this.direction = Direction.fromFace(cartDirection.getOppositeFace()); 35 | } else { 36 | this.direction = Direction.parse(dirText); 37 | } 38 | // If direction parsing fails, resolve back to alternative text and direction 39 | if (this.direction == Direction.NONE) { 40 | this.text = text; 41 | this.direction = alternative; 42 | } 43 | } 44 | // Number (counter) statements 45 | try { 46 | this.number = Integer.parseInt(this.text); 47 | } catch (NumberFormatException ex) { 48 | this.number = null; 49 | } 50 | } 51 | 52 | public boolean has(SignActionEvent event, MinecartMember member) { 53 | return Statement.has(member, this.text, event); 54 | } 55 | 56 | public boolean has(SignActionEvent event, MinecartGroup group) { 57 | return Statement.has(group, this.text, event); 58 | } 59 | 60 | public boolean hasNumber() { 61 | return this.number != null; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/BlockTrackerMember.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.block.Block; 7 | 8 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | import com.bergerkiller.bukkit.tc.detector.DetectorRegion; 11 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 12 | import com.bergerkiller.bukkit.tc.signactions.SignAction; 13 | import com.bergerkiller.bukkit.tc.signactions.SignActionType; 14 | 15 | /** 16 | * Keeps track of the active rails, signs and detector regions below a MinecartMember. 17 | * This tracker is routinely updated by the BlockTracker of the MinecartGroup. 18 | */ 19 | public class BlockTrackerMember extends BlockTracker { 20 | private final MinecartMember owner; 21 | protected List liveActiveSigns = new ArrayList(); 22 | 23 | public BlockTrackerMember(MinecartMember owner) { 24 | this.owner = owner; 25 | } 26 | 27 | /** 28 | * Gets the owner of this Block Tracker 29 | * 30 | * @return the Owner 31 | */ 32 | public MinecartMember getOwner() { 33 | return owner; 34 | } 35 | 36 | @Override 37 | public void clear() { 38 | super.clear(); 39 | if (!detectorRegions.isEmpty()) { 40 | for (DetectorRegion region : detectorRegions) { 41 | region.remove(owner); 42 | } 43 | detectorRegions.clear(); 44 | } 45 | } 46 | 47 | @Override 48 | public boolean isOnRails(Block railsBlock) { 49 | return owner.getGroup().getBlockTracker().getMemberFromRails(railsBlock) == owner; 50 | } 51 | 52 | @Override 53 | protected void onSignChange(Block signblock, boolean active) { 54 | SignActionEvent event = new SignActionEvent(signblock, owner); 55 | event.setAction(active ? SignActionType.MEMBER_ENTER : SignActionType.MEMBER_LEAVE); 56 | SignAction.executeAll(event); 57 | } 58 | 59 | @Override 60 | public void update() { 61 | super.update(); 62 | if (!owner.isUnloaded()) { 63 | MinecartGroup group = owner.getGroup(); 64 | // Member owner could be dead and have no group 65 | if (group != null) { 66 | group.getBlockTracker().update(); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/type/MinecartMemberTNT.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.type; 2 | 3 | import org.bukkit.Effect; 4 | import org.bukkit.block.BlockFace; 5 | 6 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartTNT; 7 | import com.bergerkiller.bukkit.common.wrappers.DamageSource; 8 | import com.bergerkiller.bukkit.tc.GroupUnloadedException; 9 | import com.bergerkiller.bukkit.tc.MemberMissingException; 10 | import com.bergerkiller.bukkit.tc.Util; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | 13 | public class MinecartMemberTNT extends MinecartMember { 14 | private boolean ignoreDamage = false; 15 | 16 | @Override 17 | public void onDamage(DamageSource damagesource, double damage) { 18 | if (!this.isInteractable() || ignoreDamage) { 19 | return; 20 | } 21 | super.onDamage(damagesource, damage); 22 | // If entity died and the source of the damage is 'igniting' the TNT, explode 23 | // Also explode if the TNT minecart is moving really fast 24 | if (entity.isDead() && !Util.canInstantlyBuild(damagesource.getEntity()) && 25 | (damagesource.isFireDamage() || damagesource.isExplosive() || entity.isMovingFast())) { 26 | // Important: set dead beforehand 27 | ignoreDamage = true; 28 | entity.explode(); 29 | // Entity explosion MAY have been cancelled, re-enable for the future 30 | ignoreDamage = false; 31 | } 32 | } 33 | 34 | @Override 35 | public void onActivate() { 36 | super.onActivate(); 37 | if (!entity.isTNTPrimed()) { 38 | entity.primeTNT(); 39 | } 40 | } 41 | 42 | @Override 43 | public void onPhysicsPostMove(double speedFactor) throws MemberMissingException, GroupUnloadedException { 44 | super.onPhysicsPostMove(speedFactor); 45 | int ticks = entity.getFuseTicks(); 46 | if (ticks > 0) { 47 | // Update fuse ticks and show fuse effect 48 | entity.setFuseTicks(ticks - 1); 49 | entity.getWorld().playEffect(entity.getLocation().add(0.0, 0.5, 0.0), Effect.SMOKE, BlockFace.SELF); 50 | } else if (ticks == 0) { 51 | // Explode 52 | entity.explode(); 53 | } 54 | // When hitting into a block with force - detonate 55 | if (entity.isMovementImpaired() && entity.isMovingFast()) { 56 | entity.explode(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/storage/OfflineSign.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.storage; 2 | 3 | import org.bukkit.World; 4 | import org.bukkit.block.Block; 5 | 6 | import com.bergerkiller.bukkit.common.bases.IntVector3; 7 | import com.bergerkiller.bukkit.common.utils.MaterialUtil; 8 | import com.bergerkiller.bukkit.common.utils.WorldUtil; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | 11 | public abstract class OfflineSign { 12 | 13 | public OfflineSign(IntVector3 location) { 14 | this.location = location; 15 | } 16 | 17 | private final IntVector3 location; 18 | private boolean isRemoved = false; 19 | 20 | public IntVector3 getLocation() { 21 | return this.location; 22 | } 23 | 24 | public boolean isLoaded(World world) { 25 | return world != null && world.isChunkLoaded(this.location.x >> 4, this.location.z >> 4); 26 | } 27 | 28 | public boolean isRemoved() { 29 | return this.isRemoved; 30 | } 31 | 32 | public void loadChunks(World world) { 33 | WorldUtil.loadChunks(world, this.location.x >> 4, this.location.z >> 4, 3); 34 | } 35 | 36 | public void remove(Block signBlock) { 37 | if (!this.isRemoved) { 38 | this.isRemoved = true; 39 | this.onRemove(signBlock); 40 | } 41 | } 42 | 43 | /** 44 | * Gets the sign event from this offline Sign 45 | * @param world the sign is in 46 | * @return the sign, or null if the sign isn't loaded or missing 47 | */ 48 | public SignActionEvent getSignEvent(World world) { 49 | if (this.isLoaded(world)) { 50 | Block signblock = this.location.toBlock(world); 51 | if (MaterialUtil.ISSIGN.get(signblock)) { 52 | SignActionEvent event = new SignActionEvent(signblock); 53 | if (this.validate(event)) { 54 | return event; 55 | } 56 | } 57 | this.remove(signblock); 58 | return null; 59 | } 60 | return null; 61 | } 62 | 63 | /** 64 | * Validates a sign, if returned False, onRemove is called 65 | * @param event around the sign 66 | * @return True if it is allowed, False if not 67 | */ 68 | public abstract boolean validate(SignActionEvent event); 69 | 70 | /** 71 | * Called when this sign is no longer present in the world and has to be removed 72 | * @param signBlock of the sign that is missing 73 | */ 74 | public abstract void onRemove(Block signBlock); 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/Localization.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | import org.bukkit.ChatColor; 4 | 5 | import com.bergerkiller.bukkit.common.localization.LocalizationEnum; 6 | 7 | public class Localization extends LocalizationEnum { 8 | public static final Localization COMMAND_ABOUT = new Localization("command.about", "TrainCarts %0% - See WIKI page for more information"); 9 | public static final Localization COMMAND_NOPERM = new Localization("command.noperm", ChatColor.RED + "You do not have permission, ask an admin to do this for you."); 10 | public static final Localization TICKET_ADD = new Localization("ticket.add", ChatColor.WHITE + "[Ticket System]" + ChatColor.YELLOW + " You received %0% in your bank account!"); 11 | public static final Localization TICKET_CHECK = new Localization("ticket.check", ChatColor.WHITE + "[Ticket System]" + ChatColor.YELLOW + " You currently have %0% in your bank account!"); 12 | public static final Localization TICKET_BUYFAIL = new Localization("ticket.buyfail", ChatColor.WHITE + "[Ticket System]" + ChatColor.RED + " You can't afford a Ticket for %0%, sorry."); 13 | public static final Localization TICKET_BUY = new Localization("ticket.buy", ChatColor.WHITE + "[Ticket System]" + ChatColor.YELLOW + " You bought a Ticket for %0%."); 14 | public static final Localization EDIT_NOSELECT = new Localization("edit.noselect", ChatColor.YELLOW + "You haven't selected a train to edit yet!"); 15 | public static final Localization EDIT_NOTALLOWED = new Localization("edit.notallowed", ChatColor.RED + "You are not allowed to own trains!"); 16 | public static final Localization EDIT_NONEFOUND = new Localization("edit.nonefound", ChatColor.RED + "You do not own any trains you can edit."); 17 | public static final Localization EDIT_NOTOWNED = new Localization("edit.notowned", ChatColor.RED + "You do not own this train!"); 18 | public static final Localization SELECT_DESTINATION = new Localization("select.destination", ChatColor.YELLOW + "You have selected " + ChatColor.WHITE + "%0%" + ChatColor.YELLOW + " as your destination!"); 19 | 20 | private Localization(String name, String defValue) { 21 | super(name, defValue); 22 | } 23 | 24 | @Override 25 | public String get(String... arguments) { 26 | return TrainCarts.plugin.getLocale(this.getName(), arguments); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/MemberConverter.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller; 2 | 3 | import java.util.UUID; 4 | 5 | import org.bukkit.entity.Minecart; 6 | 7 | import com.bergerkiller.bukkit.common.controller.EntityController; 8 | import com.bergerkiller.bukkit.common.conversion.CastingConverter; 9 | import com.bergerkiller.bukkit.common.conversion.Converter; 10 | import com.bergerkiller.bukkit.common.conversion.ConverterPair; 11 | import com.bergerkiller.bukkit.common.entity.CommonEntity; 12 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 13 | 14 | public class MemberConverter implements Converter> { 15 | public static final MemberConverter toMember = new MemberConverter(); 16 | 17 | @Override 18 | public MinecartMember convert(Object value, MinecartMember def) { 19 | if (value == null) { 20 | return def; 21 | } 22 | if (value instanceof UUID) { 23 | return LogicUtil.fixNull(MinecartMemberStore.getFromUID((UUID) value), def); 24 | } 25 | final MinecartMember member; 26 | if (value instanceof MinecartMember) { 27 | member = (MinecartMember) value; 28 | } else if (value instanceof Minecart) { 29 | EntityController controller = CommonEntity.get((Minecart) value).getController(); 30 | if (controller instanceof MinecartMember) { 31 | member = (MinecartMember) controller; 32 | } else { 33 | return def; 34 | } 35 | } else { 36 | return def; 37 | } 38 | if (member.isUnloaded()) { 39 | return def; 40 | } else { 41 | return member; 42 | } 43 | } 44 | 45 | @Override 46 | public final MinecartMember convert(Object value) { 47 | return convert(value, null); 48 | } 49 | 50 | @Override 51 | @SuppressWarnings({"unchecked", "rawtypes"}) 52 | public Class getOutputType() { 53 | return MinecartMember.class; 54 | } 55 | 56 | @Override 57 | public boolean isCastingSupported() { 58 | return true; 59 | } 60 | 61 | @Override 62 | public boolean isRegisterSupported() { 63 | return true; 64 | } 65 | 66 | @Override 67 | public ConverterPair, K> formPair(Converter converterB) { 68 | return new ConverterPair, K>(this, converterB); 69 | } 70 | 71 | @Override 72 | public Converter cast(Class type) { 73 | return new CastingConverter(type, this); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionJumper.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.util.Vector; 4 | 5 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 6 | import com.bergerkiller.bukkit.common.utils.MathUtil; 7 | import com.bergerkiller.bukkit.tc.Permission; 8 | import com.bergerkiller.bukkit.tc.Util; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 11 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 12 | 13 | public class SignActionJumper extends SignAction { 14 | 15 | @Override 16 | public boolean match(SignActionEvent info) { 17 | return info.isType("jump") && info.getMode() != SignActionMode.NONE; 18 | } 19 | 20 | @Override 21 | public void execute(SignActionEvent info) { 22 | if (!info.isPowered() || !info.hasMember()) { 23 | return; 24 | } 25 | final boolean isCart = info.isCartSign() && info.isAction(SignActionType.MEMBER_ENTER); 26 | final boolean isTrain = info.isTrainSign() && info.isAction(SignActionType.GROUP_ENTER); 27 | if (!isCart && !isTrain) { 28 | return; 29 | } 30 | // Parse offset 31 | Vector offset = Util.parseVector(info.getLine(2), new Vector(0.0, 0.0, 0.0)); 32 | if (offset.lengthSquared() == 0.0) { 33 | return; 34 | } 35 | // Rotate the offset so it becomes aligned with the sign 36 | float yaw = FaceUtil.faceToYaw(info.getFacing().getOppositeFace()); 37 | offset = MathUtil.rotate(yaw, 0.0f, offset); 38 | // Jump 39 | if (isCart) { 40 | jump(info.getMember(), offset); 41 | } else { 42 | for (MinecartMember member : info.getGroup()) { 43 | jump(member, offset.clone()); 44 | } 45 | } 46 | } 47 | 48 | @Override 49 | public boolean build(SignChangeActionEvent info) { 50 | if (info.isCartSign()) { 51 | return handleBuild(info, Permission.BUILD_JUMPER, "cart jumper", "cause a minecart to jump towards a certain direction"); 52 | } else if (info.isTrainSign()) { 53 | return handleBuild(info, Permission.BUILD_JUMPER, "train jumper", "cause an entire train to jump towards a certain direction"); 54 | } 55 | return false; 56 | } 57 | 58 | public static void jump(MinecartMember member, Vector offset) { 59 | //TODO: Proper jumping action for accurate (block location) jump 60 | member.getEntity().vel.set(offset); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/logic/RailLogicAir.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.logic; 2 | 3 | import org.bukkit.block.BlockFace; 4 | import org.bukkit.util.Vector; 5 | 6 | import com.bergerkiller.bukkit.common.bases.IntVector3; 7 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 8 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 9 | import com.bergerkiller.bukkit.common.utils.MathUtil; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | 12 | /** 13 | * Handles movement of a minecart that is flying through the air 14 | */ 15 | public class RailLogicAir extends RailLogic { 16 | public static final RailLogicAir INSTANCE = new RailLogicAir(); 17 | 18 | private RailLogicAir() { 19 | super(BlockFace.SELF); 20 | } 21 | 22 | @Override 23 | public BlockFace getMovementDirection(MinecartMember member, Vector movement) { 24 | if (member.isMovingVerticalOnly()) { 25 | return FaceUtil.getVertical(movement.getY() > 0.0); 26 | } else { 27 | return FaceUtil.getDirection(movement); 28 | } 29 | } 30 | 31 | @Override 32 | public void setForwardVelocity(MinecartMember member, double force) { 33 | if (member.isMovementControlled()) { 34 | // Be sure to use the direction, we are being controlled! 35 | super.setForwardVelocity(member, force); 36 | } else { 37 | // Simply set vector length 38 | Vector vel = member.getEntity().vel.vector(); 39 | MathUtil.setVectorLength(vel, force); 40 | member.getEntity().vel.set(vel); 41 | } 42 | } 43 | 44 | @Override 45 | public boolean hasVerticalMovement() { 46 | return true; 47 | } 48 | 49 | @Override 50 | public Vector getFixedPosition(CommonMinecart entity, double x, double y, double z, IntVector3 railPos) { 51 | return new Vector(x, y, z); 52 | } 53 | 54 | @Override 55 | public void onPreMove(MinecartMember member) { 56 | // Only do this logic if the head is is not moving vertically 57 | // Or if this member is the head, of course 58 | if (member.isMovingVerticalOnly() && member.getEntity().vel.getY() > 0.0) { 59 | MinecartMember head = member.getGroup().head(); 60 | if (member != head && head.isMovingVerticalOnly()) { 61 | return; 62 | } 63 | } 64 | // Apply flying friction 65 | if (!member.isMovementControlled()) { 66 | member.getEntity().vel.multiply(member.getEntity().getFlyingVelocityMod()); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypePowered.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.block.BlockFace; 5 | 6 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 7 | import com.bergerkiller.bukkit.common.utils.MaterialUtil; 8 | import com.bergerkiller.bukkit.common.utils.MathUtil; 9 | import com.bergerkiller.bukkit.tc.TrainCarts; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | 12 | public class RailTypePowered extends RailTypeRegular { 13 | public static final double START_BOOST = 0.02; 14 | private final boolean isPowered; 15 | 16 | protected RailTypePowered(boolean isPowered) { 17 | this.isPowered = isPowered; 18 | } 19 | 20 | public boolean isPowered() { 21 | return this.isPowered; 22 | } 23 | 24 | @Override 25 | public void onPreMove(MinecartMember member) { 26 | // Do not do anything if being controlled 27 | if (member.isMovementControlled()) { 28 | return; 29 | } 30 | 31 | CommonMinecart entity = member.getEntity(); 32 | if (!this.isPowered) { 33 | // Perform braking 34 | if (entity.vel.xz.lengthSquared() < 0.0009) { 35 | entity.vel.multiply(0.0); 36 | } else { 37 | entity.vel.multiply(0.5); 38 | } 39 | } else { 40 | // Perform launching 41 | double motLength = entity.vel.xz.length(); 42 | if (motLength > 0.01) { 43 | // Simple motion boosting when already moving 44 | entity.vel.xz.add(entity.vel.xz, TrainCarts.poweredRailBoost / motLength); 45 | } else { 46 | // Launch away from a suffocating block 47 | BlockFace dir = member.getRailDirection(); 48 | org.bukkit.block.Block block = member.getBlock(); 49 | boolean pushFrom1 = MaterialUtil.SUFFOCATES.get(block.getRelative(dir.getOppositeFace())); 50 | boolean pushFrom2 = MaterialUtil.SUFFOCATES.get(block.getRelative(dir)); 51 | // If pushing from both directions, block all movement 52 | if (pushFrom1 && pushFrom2) { 53 | entity.vel.xz.setZero(); 54 | } else if (pushFrom1 != pushFrom2) { 55 | // Boosting to the open spot 56 | final double boost = MathUtil.invert(START_BOOST, pushFrom2); 57 | entity.vel.xz.set(boost * dir.getModX(), boost * dir.getModZ()); 58 | } 59 | } 60 | } 61 | } 62 | 63 | @Override 64 | public boolean isRail(Material type, int data) { 65 | return type == Material.POWERED_RAIL && ((data & 0x8) == 0x8) == isPowered; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionLauncher.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 6 | import com.bergerkiller.bukkit.tc.Direction; 7 | import com.bergerkiller.bukkit.tc.Permission; 8 | import com.bergerkiller.bukkit.tc.TrainCarts; 9 | import com.bergerkiller.bukkit.tc.Util; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 11 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 12 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 13 | 14 | public class SignActionLauncher extends SignAction { 15 | 16 | @Override 17 | public boolean match(SignActionEvent info) { 18 | return info.isType("launch"); 19 | } 20 | 21 | @Override 22 | public void execute(SignActionEvent info) { 23 | if (!info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON) || !info.isPowered()) { 24 | return; 25 | } 26 | // Parse the launch speed 27 | double velocity = ParseUtil.parseDouble(info.getLine(2), TrainCarts.launchForce); 28 | 29 | // Parse the launch distance 30 | double distance = ParseUtil.parseDouble(info.getLine(1), 1.0); 31 | 32 | if (info.isRCSign()) { 33 | boolean reverse = Direction.parse(info.getLine(3)) == Direction.BACKWARD; 34 | 35 | // Launch all groups 36 | for (MinecartGroup group : info.getRCTrainGroups()) { 37 | if (reverse) { 38 | group.reverse(); 39 | } 40 | group.head().getActions().addActionLaunch(distance, velocity); 41 | } 42 | } else if (info.hasRailedMember()) { 43 | // Parse the direction to launch into 44 | BlockFace direction = Direction.parse(info.getLine(3)).getDirection(info.getFacing(), info.getCartDirection()); 45 | 46 | // Calculate the launch distance if left empty 47 | if (distance <= 0.0) { 48 | distance = Util.calculateStraightLength(info.getRails(), direction); 49 | } 50 | 51 | // Launch 52 | info.getMember().getActions().addActionLaunch(direction, distance, velocity); 53 | } 54 | } 55 | 56 | public void execute(MinecartGroup group) { 57 | 58 | } 59 | 60 | @Override 61 | public boolean canSupportRC() { 62 | return true; 63 | } 64 | 65 | @Override 66 | public boolean build(SignChangeActionEvent event) { 67 | if (event.getMode() != SignActionMode.NONE) { 68 | return handleBuild(event, Permission.BUILD_LAUNCHER, "launcher", "launch (or brake) trains at a desired speed"); 69 | } 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/logic/RailLogicVerticalSlopeDown.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.logic; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.bases.IntVector3; 6 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 7 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 8 | import com.bergerkiller.bukkit.common.utils.MathUtil; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | 11 | /** 12 | * Handles the rail logic of a sloped rail with a vertical rail above 13 | */ 14 | public class RailLogicVerticalSlopeDown extends RailLogicSloped { 15 | private static final RailLogicVerticalSlopeDown[] values = new RailLogicVerticalSlopeDown[4]; 16 | static { 17 | for (int i = 0; i < 4; i++) { 18 | values[i] = new RailLogicVerticalSlopeDown(FaceUtil.notchToFace(i << 1)); 19 | } 20 | } 21 | 22 | private RailLogicVerticalSlopeDown(BlockFace direction) { 23 | super(direction); 24 | } 25 | 26 | @Override 27 | public void onPostMove(MinecartMember member) { 28 | final CommonMinecart entity = member.getEntity(); 29 | final IntVector3 block = member.getBlockPos(); 30 | 31 | // First: check whether the Minecart is moving up this slope 32 | // If moving down, simply use the Sloped logic in the underlying super Class 33 | if (member.getDirectionTo() == this.getDirection().getOppositeFace()) { 34 | super.onPostMove(member); 35 | return; 36 | } 37 | 38 | double factor = 0.0; 39 | if (this.alongZ) { 40 | factor = this.getDirection().getModZ() * (block.midZ() - entity.loc.getZ()); 41 | } else if (this.alongX) { 42 | factor = this.getDirection().getModX() * (block.midX() - entity.loc.getX()); 43 | } 44 | double posYAdd = (0.5 - MathUtil.clamp(factor, 0.0, 0.5)) * 2.0; 45 | entity.loc.y.set(block.y + posYAdd); 46 | if (posYAdd >= 1.0) { 47 | // Go to the vertical rail 48 | entity.loc.y.add(1.0); 49 | entity.loc.x.set(block.midX()); 50 | entity.loc.z.set(block.midZ()); 51 | // Turn velocity to the vertical type 52 | entity.vel.y.set(entity.vel.xz.length()); 53 | entity.vel.xz.setZero(); 54 | } 55 | } 56 | 57 | /** 58 | * Gets the sloped-vertical rail logic for the the sloped track leading upwards facing the direction specified 59 | * 60 | * @param direction of the sloped rail 61 | * @return Rail Logic 62 | */ 63 | public static RailLogicVerticalSlopeDown get(BlockFace direction) { 64 | return values[FaceUtil.faceToNotch(direction) >> 1]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionWaitOccupied.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.block.BlockFace; 5 | 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMemberStore; 8 | import com.bergerkiller.bukkit.tc.utils.TrackIterator; 9 | 10 | public class MemberActionWaitOccupied extends MemberAction implements WaitAction { 11 | private BlockFace direction; 12 | private Block start; 13 | private final int maxsize; 14 | private final long delay; 15 | private final double launchDistance; 16 | private double launchforce; 17 | private int counter = 20; 18 | private boolean breakCode = false; 19 | 20 | public MemberActionWaitOccupied(final int maxsize, final long delay, final double launchDistance) { 21 | this.maxsize = maxsize; 22 | this.delay = delay; 23 | this.launchDistance = launchDistance; 24 | } 25 | 26 | @Override 27 | public void bind() { 28 | this.direction = getMember().getDirectionTo(); 29 | this.start = getMember().getBlock(); 30 | this.launchforce = this.getGroup().getAverageForce(); 31 | } 32 | 33 | @Override 34 | public void start() { 35 | if (this.handleOccupied()) { 36 | this.getGroup().stop(true); 37 | } else { 38 | breakCode = true; 39 | } 40 | } 41 | 42 | public boolean handleOccupied() { 43 | return handleOccupied(this.start, this.direction, this.getMember(), this.maxsize); 44 | } 45 | public static boolean handleOccupied(Block start, BlockFace direction, MinecartMember ignore, int maxdistance) { 46 | TrackIterator iter = new TrackIterator(start, direction); 47 | while (iter.hasNext() && --maxdistance >= 0) { 48 | MinecartMember mm = MinecartMemberStore.getAt(iter.next()); 49 | if (mm != null && mm.getGroup() != ignore.getGroup()) { 50 | ignore.setIgnoreCollisions(true); 51 | return true; 52 | } 53 | } 54 | ignore.setIgnoreCollisions(false); 55 | return false; 56 | } 57 | 58 | @Override 59 | public boolean update() { 60 | if (breakCode) return true; 61 | if (counter++ >= 20) { 62 | if (!this.handleOccupied()) { 63 | //launch 64 | if (this.delay > 0) { 65 | this.getGroup().getActions().addActionWait(this.delay); 66 | } 67 | this.getMember().getActions().addActionLaunch(this.direction, this.launchDistance, this.launchforce); 68 | return true; 69 | } else { 70 | //this.wasoccupied = this.handleOccupied(); 71 | } 72 | counter = 0; 73 | } 74 | return false; 75 | } 76 | 77 | @Override 78 | public boolean isMovementSuppressed() { 79 | return true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/logic/RailLogicVertical.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.logic; 2 | 3 | import org.bukkit.block.BlockFace; 4 | import org.bukkit.util.Vector; 5 | 6 | import com.bergerkiller.bukkit.common.bases.IntVector3; 7 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 8 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 9 | import com.bergerkiller.bukkit.tc.Util; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | 12 | public class RailLogicVertical extends RailLogic { 13 | private static final RailLogicVertical[] values = new RailLogicVertical[4]; 14 | static { 15 | for (int i = 0; i < 4; i++) { 16 | values[i] = new RailLogicVertical(FaceUtil.notchToFace(i << 1)); 17 | } 18 | } 19 | 20 | private RailLogicVertical(BlockFace direction) { 21 | super(direction); 22 | } 23 | 24 | @Override 25 | public BlockFace getMovementDirection(MinecartMember member, Vector movement) { 26 | return Util.getVerticalFace(movement.getY() > 0.0); 27 | } 28 | 29 | @Override 30 | public double getForwardVelocity(MinecartMember member) { 31 | return member.getDirection().getModY() * member.getEntity().vel.getY(); 32 | } 33 | 34 | @Override 35 | public Vector getFixedPosition(CommonMinecart entity, double x, double y, double z, IntVector3 railPos) { 36 | return new Vector(railPos.midX(), y, railPos.midZ()); 37 | } 38 | 39 | @Override 40 | public void setForwardVelocity(MinecartMember member, double force) { 41 | member.getEntity().vel.setY(member.getDirection().getModY() * force); 42 | } 43 | 44 | @Override 45 | public boolean hasVerticalMovement() { 46 | return true; 47 | } 48 | 49 | @Override 50 | public double getGravityMultiplier(MinecartMember member) { 51 | return member.getGroup().getProperties().isSlowingDown() ? MinecartMember.VERTRAIL_MULTIPLIER : 0.0; 52 | } 53 | 54 | @Override 55 | public void onPreMove(MinecartMember member) { 56 | final CommonMinecart entity = member.getEntity(); 57 | // Horizontal rail force to motY 58 | entity.vel.y.add(entity.vel.xz.length() * member.getDirection().getModY()); 59 | entity.vel.xz.setZero(); 60 | // Position update 61 | entity.loc.set(this.getFixedPosition(entity, entity.loc.getX(), entity.loc.getY(), entity.loc.getZ(), member.getBlockPos())); 62 | } 63 | 64 | /** 65 | * Gets the vertical rail logic for the direction specified 66 | * 67 | * @param direction of the rail 68 | * @param upSlope whether the minecart went up from a slope 69 | * @return Rail Logic 70 | */ 71 | public static RailLogicVertical get(BlockFace direction) { 72 | return values[FaceUtil.faceToNotch(direction) >> 1]; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionBlocker.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.common.utils.CommonUtil; 6 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 7 | import com.bergerkiller.bukkit.tc.Permission; 8 | import com.bergerkiller.bukkit.tc.Direction; 9 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitState; 10 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 11 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 12 | 13 | public class SignActionBlocker extends SignAction { 14 | 15 | @Override 16 | public boolean match(SignActionEvent info) { 17 | return info.isType("blocker"); 18 | } 19 | 20 | @Override 21 | public void execute(SignActionEvent info) { 22 | if (info.getMode() != SignActionMode.NONE && info.hasRailedMember()) { 23 | if (info.isAction(SignActionType.GROUP_LEAVE) || (info.isAction(SignActionType.REDSTONE_CHANGE) && !info.isPowered())) { 24 | // Remove the wait state when the train leaves or the sign lost power to block 25 | GroupActionWaitState action = CommonUtil.tryCast(info.getGroup().getActions().getCurrentAction(), GroupActionWaitState.class); 26 | if (action != null) { 27 | action.stop(); 28 | } 29 | } else if (info.isPowered() && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_CHANGE, SignActionType.MEMBER_MOVE)) { 30 | // Set the next direction based on the sign 31 | // Don't do this in the move event as that one fires too often (performance issue) 32 | if (!info.isAction(SignActionType.MEMBER_MOVE)) { 33 | Direction direction = Direction.parse(info.getLine(3)); 34 | if (direction != Direction.NONE) { 35 | long delay = ParseUtil.parseTime(info.getLine(2)); 36 | BlockFace trainDirection = direction.getDirection(info.getFacing(), info.getCartDirection()); 37 | info.getGroup().getActions().clear(); 38 | info.getGroup().getActions().addActionWaitState(); 39 | if (delay > 0) { 40 | info.getGroup().getActions().addActionWait(delay); 41 | } 42 | info.getMember().getActions().addActionLaunch(trainDirection, 2.0, info.getGroup().getAverageForce()); 43 | } 44 | } 45 | // Stop the train, if right after moving, also cancel a previous positional change 46 | info.getGroup().stop(info.isAction(SignActionType.MEMBER_MOVE)); 47 | } 48 | } 49 | } 50 | 51 | @Override 52 | public boolean build(SignChangeActionEvent event) { 53 | if (event.getMode() != SignActionMode.NONE) { 54 | return handleBuild(event, Permission.BUILD_BLOCKER, "train blocker", "block trains coming from a certain direction"); 55 | } 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/ActionTrackerGroup.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import com.bergerkiller.bukkit.tc.actions.Action; 4 | import com.bergerkiller.bukkit.tc.actions.GroupAction; 5 | import com.bergerkiller.bukkit.tc.actions.GroupActionRefill; 6 | import com.bergerkiller.bukkit.tc.actions.GroupActionSizzle; 7 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitDelay; 8 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitForever; 9 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitState; 10 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitTicks; 11 | import com.bergerkiller.bukkit.tc.actions.GroupActionWaitTill; 12 | import com.bergerkiller.bukkit.tc.actions.MemberAction; 13 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 14 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 15 | 16 | public class ActionTrackerGroup extends ActionTracker { 17 | private final MinecartGroup owner; 18 | 19 | public ActionTrackerGroup(MinecartGroup owner) { 20 | this.owner = owner; 21 | } 22 | 23 | /** 24 | * Gets the owner of this Block Tracker 25 | * 26 | * @return the Owner 27 | */ 28 | public MinecartGroup getOwner() { 29 | return owner; 30 | } 31 | 32 | @Override 33 | public void clear() { 34 | super.clear(); 35 | for (MinecartMember member : owner) { 36 | member.getActions().clear(); 37 | } 38 | } 39 | 40 | @Override 41 | public T addAction(T action) { 42 | if (action instanceof GroupAction) { 43 | ((GroupAction) action).setGroup(owner); 44 | } else if (action instanceof MemberAction && ((MemberAction) action).getMember() == null) { 45 | throw new RuntimeException("Can not add member action without a member set beforehand!"); 46 | } 47 | return super.addAction(action); 48 | } 49 | 50 | public GroupActionWaitDelay addActionWait(long delay) { 51 | return this.addAction(new GroupActionWaitDelay(delay)); 52 | } 53 | 54 | public GroupActionWaitTill addActionWaitTill(long time) { 55 | return this.addAction(new GroupActionWaitTill(time)); 56 | } 57 | 58 | public GroupActionWaitTicks addActionWaitTicks(int ticks) { 59 | return this.addAction(new GroupActionWaitTicks(ticks)); 60 | } 61 | 62 | public GroupActionWaitForever addActionWaitForever() { 63 | return this.addAction(new GroupActionWaitForever()); 64 | } 65 | 66 | public GroupActionWaitState addActionWaitState() { 67 | return this.addAction(new GroupActionWaitState()); 68 | } 69 | 70 | public GroupActionSizzle addActionSizzle() { 71 | return this.addAction(new GroupActionSizzle()); 72 | } 73 | 74 | public GroupActionRefill addActionRefill() { 75 | return this.addAction(new GroupActionRefill()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/itemanimation/ItemAnimatedInventory.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.itemanimation; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | import com.bergerkiller.bukkit.common.inventory.InventoryBase; 7 | import com.bergerkiller.bukkit.common.utils.ItemUtil; 8 | import com.bergerkiller.bukkit.tc.utils.GroundItemsInventory; 9 | 10 | /** 11 | * Redirects calls to a base inventory, while showing item animations during item transfers 12 | */ 13 | public class ItemAnimatedInventory extends InventoryBase { 14 | private Object other, self; 15 | private final Inventory source; 16 | private final ItemStack[] original; 17 | 18 | public ItemAnimatedInventory(Inventory inventory, Object self, Object other) { 19 | this.other = other; 20 | this.self = self; 21 | this.source = inventory; 22 | this.original = ItemUtil.getClonedContents(inventory); 23 | } 24 | 25 | public static Inventory convert(Inventory inventory, Object self, Object other) { 26 | return new ItemAnimatedInventory(inventory, self, other); 27 | } 28 | 29 | @Override 30 | public void setItem(int index, ItemStack newitem) { 31 | ItemStack olditem = this.original[index]; 32 | this.source.setItem(index, newitem); 33 | Object self = this.getSelfAt(index); 34 | this.original[index] = ItemUtil.cloneItem(newitem); 35 | if (olditem == null) { 36 | if (newitem != null) { 37 | ItemAnimation.start(other, self, newitem); 38 | } 39 | } else { 40 | if (newitem == null) { 41 | ItemAnimation.start(self, other, olditem); 42 | } else { 43 | //same type? 44 | if (ItemUtil.equalsIgnoreAmount(olditem, newitem)) { 45 | // Obtain an item stack (trans) to do an animation with 46 | // Switch between self and other based on changed amount 47 | ItemStack trans = ItemUtil.cloneItem(newitem); 48 | int newAmount = trans.getAmount() - olditem.getAmount(); 49 | if (newAmount > 0) { 50 | trans.setAmount(newAmount); 51 | ItemAnimation.start(other, self, trans); 52 | } else if (newAmount < 0) { 53 | trans.setAmount(-newAmount); 54 | ItemAnimation.start(self, other, trans); 55 | } 56 | } else { 57 | //swap 58 | ItemAnimation.start(self, other, olditem); 59 | ItemAnimation.start(other, self, newitem); 60 | } 61 | } 62 | } 63 | } 64 | 65 | public Object getSelfAt(int index) { 66 | if (this.source instanceof GroundItemsInventory) { 67 | return ((GroundItemsInventory) this.source).getEntity(index); 68 | } 69 | return self; 70 | } 71 | 72 | @Override 73 | public ItemStack getItem(int index) { 74 | return this.source.getItem(index); 75 | } 76 | 77 | @Override 78 | public int getSize() { 79 | return this.source.getSize(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/ActionTracker.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | import com.bergerkiller.bukkit.tc.actions.Action; 8 | import com.bergerkiller.bukkit.tc.actions.MemberAction; 9 | import com.bergerkiller.bukkit.tc.actions.MovementAction; 10 | import com.bergerkiller.bukkit.tc.actions.WaitAction; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | 13 | /** 14 | * Stores actions and updates them per tick 15 | */ 16 | public class ActionTracker { 17 | private final Queue actions = new LinkedList(); 18 | 19 | public boolean hasAction() { 20 | return this.actions.size() > 0; 21 | } 22 | 23 | /** 24 | * Clears all actions scheduled for the owner of this Action Tracker. 25 | * For groups, this also clears all the actions scheduled for individual members. 26 | */ 27 | public void clear() { 28 | this.actions.clear(); 29 | } 30 | 31 | /** 32 | * Removes all Actions running for a specific minecart 33 | * 34 | * @param forMember to remove the actions for 35 | */ 36 | public void removeActions(MinecartMember forMember) { 37 | Iterator iter = this.actions.iterator(); 38 | while (iter.hasNext()) { 39 | Action action = iter.next(); 40 | if (action instanceof MemberAction && ((MemberAction) action).getMember() == forMember) { 41 | iter.remove(); 42 | } 43 | } 44 | } 45 | 46 | /** 47 | * Removes and returns the current action 48 | * 49 | * @return action removed, or null if there was none 50 | */ 51 | public Action removeAction() { 52 | return this.actions.remove(); 53 | } 54 | 55 | /** 56 | * Adds a new action to be scheduled for this member or group 57 | * 58 | * @param action to be executed 59 | * @return the action that was added 60 | */ 61 | public T addAction(T action) { 62 | this.actions.offer(action); 63 | action.bind(); 64 | return action; 65 | } 66 | 67 | /** 68 | * Gets whether an action is controlling this train. 69 | * When this is True, no physics should be applied. 70 | * 71 | * @return True if movement is controlled by an action, False if not 72 | */ 73 | public boolean isMovementControlled() { 74 | final Action a = this.getCurrentAction(); 75 | return a instanceof MovementAction && ((MovementAction) a).isMovementSuppressed(); 76 | } 77 | 78 | public boolean isWaitAction() { 79 | return this.getCurrentAction() instanceof WaitAction; 80 | } 81 | 82 | public Action getCurrentAction() { 83 | return this.actions.peek(); 84 | } 85 | 86 | public void doTick() { 87 | if (this.hasAction() && this.actions.peek().doTick()) { 88 | this.actions.remove(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementProperty.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import java.util.ArrayList; 4 | 5 | import com.bergerkiller.bukkit.tc.CollisionMode; 6 | import com.bergerkiller.bukkit.tc.Util; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | import com.bergerkiller.bukkit.tc.properties.CartProperties; 11 | import com.bergerkiller.bukkit.tc.properties.TrainProperties; 12 | 13 | public class StatementProperty extends Statement { 14 | private ArrayList properties = new ArrayList(); 15 | private String[] maxspeed; 16 | private String[] playerEnter; 17 | private String[] playerExit; 18 | private String[] mobEnter; 19 | public StatementProperty() { 20 | maxspeed = add("maxspeed", "speedlimit"); 21 | playerEnter = add("playerenter", "playersenter"); 22 | playerExit = add("playerexit", "playersexit"); 23 | mobEnter = add("mobenter", "mobsenter"); 24 | } 25 | 26 | private String[] add(String... properties) { 27 | for (String property : properties) { 28 | this.properties.add(property); 29 | } 30 | return properties; 31 | } 32 | 33 | private boolean match(String[] property, String text) { 34 | for (String propval : property) { 35 | if (text.startsWith(propval)) { 36 | return true; 37 | } 38 | } 39 | return false; 40 | } 41 | 42 | @Override 43 | public boolean match(String text) { 44 | for (String property : properties) { 45 | if (text.startsWith(property)) { 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | @Override 53 | public boolean matchArray(String text) { 54 | return false; 55 | } 56 | 57 | @Override 58 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 59 | TrainProperties prop = group.getProperties(); 60 | String lower = text.toLowerCase(); 61 | if (match(maxspeed, lower)) { 62 | return Util.evaluate(prop.getSpeedLimit(), text); 63 | } else if (match(playerEnter, lower)) { 64 | return prop.getPlayersEnter(); 65 | } else if (match(playerExit, lower)) { 66 | return prop.getPlayersExit(); 67 | } else if (match(mobEnter, lower)) { 68 | return prop.mobCollision == CollisionMode.ENTER; 69 | } 70 | 71 | // Perform checks on cart properties 72 | return super.handle(group, text, event); 73 | } 74 | 75 | @Override 76 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 77 | CartProperties prop = member.getProperties(); 78 | String lower = text.toLowerCase(); 79 | if (match(playerEnter, lower)) { 80 | return prop.getPlayersEnter(); 81 | } else if (match(playerExit, lower)) { 82 | return prop.getPlayersExit(); 83 | } 84 | return false; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/TrackWalkIterator.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.tc.TrainCarts; 8 | import com.bergerkiller.bukkit.tc.rails.type.RailType; 9 | 10 | /* 11 | * A wrapper around the track iterator, which walks along the tracks 12 | * The walk step distance can be set 13 | */ 14 | public class TrackWalkIterator { 15 | private double stepsize = TrainCarts.cartDistance; 16 | private Location current, next; 17 | private final TrackWalkingPoint walker; 18 | 19 | /** 20 | * Constructs a new walking iterator 21 | * 22 | * @param startRail (NOT position block) 23 | * @param direction to start walking into 24 | */ 25 | public TrackWalkIterator(Block startRail, BlockFace direction) { 26 | Block startBlock = RailType.getType(startRail).findMinecartPos(startRail); 27 | Location startLoc = startBlock == null ? null : startBlock.getLocation().add(0.5, 0.5, 0.5); 28 | this.walker = new TrackWalkingPoint(startLoc, startRail, direction); 29 | this.current = this.next = walker.currentPosition == null ? null : walker.currentPosition.clone(); 30 | } 31 | 32 | /** 33 | * Constructs a new walking iterator 34 | * 35 | * @param start position of the Minecart (NOT the rails!) 36 | * @param direction to start walking into 37 | */ 38 | public TrackWalkIterator(Location start, BlockFace direction) { 39 | Block railsBlock = null; 40 | Block startBlock = start.getBlock(); 41 | for (RailType type : RailType.values()) { 42 | if ((railsBlock = type.findRail(startBlock)) != null) { 43 | break; 44 | } 45 | } 46 | this.walker = new TrackWalkingPoint(start, railsBlock, direction); 47 | this.current = this.next = this.walker.currentPosition.clone(); 48 | } 49 | 50 | public TrackWalkIterator setStep(double size) { 51 | this.stepsize = size; 52 | return this; 53 | } 54 | 55 | private void genNext() { 56 | this.next = walker.move(stepsize) ? walker.currentPosition.clone() : null; 57 | } 58 | 59 | public boolean hasNext() { 60 | return this.next != null; 61 | } 62 | 63 | public Location current() { 64 | return this.current; 65 | } 66 | 67 | public Location peekNext() { 68 | return this.next; 69 | } 70 | 71 | public Location next() { 72 | this.current = this.next; 73 | this.genNext(); 74 | return this.current; 75 | } 76 | 77 | public static Location[] walk(Block start, BlockFace direction, int size, double stepsize) { 78 | TrackWalkIterator iter = new TrackWalkIterator(start, direction); 79 | Location[] rval = new Location[size]; 80 | for (int i = 0; i < size; i++) { 81 | if (iter.hasNext()) { 82 | rval[i] = iter.next(); 83 | } else { 84 | rval[i] = rval[i - 1]; 85 | } 86 | } 87 | return rval; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionProperties.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import java.util.Locale; 4 | 5 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 6 | import com.bergerkiller.bukkit.tc.Permission; 7 | import com.bergerkiller.bukkit.tc.Util; 8 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 9 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 10 | import com.bergerkiller.bukkit.tc.properties.IParsable; 11 | import com.bergerkiller.bukkit.tc.properties.TrainProperties; 12 | 13 | public class SignActionProperties extends SignAction { 14 | 15 | @Override 16 | public boolean match(SignActionEvent info) { 17 | return info.isType("property"); 18 | } 19 | 20 | @Override 21 | public void execute(SignActionEvent info) { 22 | final boolean powerChange = info.isAction(SignActionType.REDSTONE_ON, SignActionType.REDSTONE_OFF); 23 | if ((powerChange || info.isAction(SignActionType.MEMBER_ENTER)) && info.isCartSign() && info.hasMember()) { 24 | parseSet(info.getMember(), info); 25 | } else if ((powerChange || info.isAction(SignActionType.GROUP_ENTER)) && info.isTrainSign() && info.hasGroup()) { 26 | parseSet(info.getGroup(), info); 27 | } else if (powerChange && info.isRCSign()) { 28 | for (TrainProperties prop : info.getRCTrainProperties()) { 29 | parseSet(prop, info); 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public boolean build(SignChangeActionEvent event) { 36 | if (event.isCartSign()) { 37 | return handleBuild(event, Permission.BUILD_PROPERTY, "cart property setter", "set properties on the cart above"); 38 | } else if (event.isTrainSign()) { 39 | return handleBuild(event, Permission.BUILD_PROPERTY, "train property setter", "set properties on the train above"); 40 | } else if (event.isRCSign()) { 41 | return handleBuild(event, Permission.BUILD_PROPERTY, "train property setter", "remotely set properties on the train specified"); 42 | } 43 | return false; 44 | } 45 | 46 | @Override 47 | public boolean canSupportRC() { 48 | return true; 49 | } 50 | 51 | private static boolean argsUsesSeparator(String mode) { 52 | return LogicUtil.contains(mode, "exitoffset", "exitrot", "exitrotation"); 53 | } 54 | 55 | private static boolean parseSet(IParsable properties, SignActionEvent info) { 56 | String mode = info.getLine(2).toLowerCase(Locale.ENGLISH).trim(); 57 | if (argsUsesSeparator(mode)) { 58 | return Util.parseProperties(properties, mode, info.getLine(3)); 59 | } 60 | String[] args = Util.splitBySeparator(info.getLine(3)); 61 | if (args.length >= 2) { 62 | return Util.parseProperties(properties, mode, info.isPowered() ? args[0] : args[1]); 63 | } else if (args.length == 1 && info.isPowered()) { 64 | return Util.parseProperties(properties, mode, args[0]); 65 | } else { 66 | return false; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/actions/MemberActionLaunch.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.actions; 2 | 3 | import com.bergerkiller.bukkit.common.utils.MathUtil; 4 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 5 | 6 | public class MemberActionLaunch extends MemberAction implements MovementAction { 7 | private static final double minVelocity = 0.02; 8 | private static final double minVelocityForLaunch = 0.004; 9 | private double distance; 10 | private double targetdistance; 11 | private double targetvelocity; 12 | private double startvelocity; 13 | 14 | public MemberActionLaunch(double targetdistance, double targetvelocity) { 15 | this.distance = 0; 16 | this.targetdistance = targetdistance; 17 | this.targetvelocity = targetvelocity; 18 | this.distance = 0; 19 | } 20 | 21 | protected void setTargetDistance(double distance) { 22 | this.targetdistance = distance; 23 | } 24 | 25 | @Override 26 | public void start() { 27 | this.startvelocity = MathUtil.clamp(this.getMember().getForce(), this.getEntity().getMaxSpeed()); 28 | if (this.startvelocity < minVelocity) { 29 | this.startvelocity = minVelocity; 30 | } 31 | } 32 | 33 | @Override 34 | public boolean isMovementSuppressed() { 35 | return true; 36 | } 37 | 38 | public double getTargetVelocity() { 39 | return this.targetvelocity; 40 | } 41 | public double getTargetDistance() { 42 | return this.targetdistance; 43 | } 44 | public double getDistance() { 45 | return this.distance; 46 | } 47 | 48 | @Override 49 | public boolean update() { 50 | // Abort when derailed. We do permit vertical 'air-launching' 51 | if (this.getMember().isDerailed() && !this.getMember().isMovingVerticalOnly()) { 52 | return true; 53 | } 54 | 55 | // Did any of the carts in the group stop? 56 | if (this.distance != 0) { 57 | for (MinecartMember mm : this.getGroup()) { 58 | if (mm.getForceSquared() < minVelocityForLaunch * minVelocityForLaunch) { 59 | //stopped 60 | return true; 61 | } 62 | } 63 | } 64 | 65 | //Increment distance 66 | this.distance += this.getEntity().getMovedDistance(); 67 | 68 | //Reached the target distance? 69 | if (this.distance > this.targetdistance - 0.2) { 70 | // Finish with the desired end-velocity 71 | this.getGroup().setForwardForce(this.targetvelocity); 72 | return true; 73 | } else { 74 | //Get the velocity to set the carts to 75 | double targetvel = MathUtil.clamp(this.targetvelocity, this.getEntity().getMaxSpeed()); 76 | if (this.targetvelocity > 0 || (this.targetdistance - this.distance) < 5) { 77 | targetvel = MathUtil.lerp(this.startvelocity, targetvel, this.distance / this.targetdistance); 78 | } else { 79 | targetvel = this.startvelocity; 80 | } 81 | targetvel = Math.max(targetvel, minVelocity); 82 | this.getGroup().setForwardForce(targetvel); 83 | return false; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionTeleport.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.mw.MyWorlds; 8 | import com.bergerkiller.bukkit.mw.Portal; 9 | import com.bergerkiller.bukkit.tc.Permission; 10 | import com.bergerkiller.bukkit.tc.TrainCarts; 11 | import com.bergerkiller.bukkit.tc.Util; 12 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 13 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 14 | import com.bergerkiller.bukkit.tc.utils.BlockTimeoutMap; 15 | import com.bergerkiller.bukkit.common.utils.BlockUtil; 16 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 17 | import com.bergerkiller.bukkit.common.utils.MaterialUtil; 18 | 19 | public class SignActionTeleport extends SignAction { 20 | private BlockTimeoutMap teleportTimes = new BlockTimeoutMap(); 21 | 22 | @Override 23 | public boolean match(SignActionEvent info) { 24 | return TrainCarts.MyWorldsEnabled && info.getLine(0).equalsIgnoreCase("[portal]") && info.hasRails(); 25 | } 26 | 27 | @Override 28 | public void execute(SignActionEvent info) { 29 | if (!info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON) || !info.hasGroup() || !info.isPowered()) { 30 | return; 31 | } 32 | Portal portal = Portal.get(info.getLocation()); 33 | if (portal == null) { 34 | return; 35 | } 36 | String destname = portal.getDestinationName(); 37 | Location dest = Portal.getPortalLocation(destname, info.getGroup().getWorld().getName()); 38 | if (dest != null) { 39 | //Teleport the ENTIRE train to the destination... 40 | Block sign = dest.getBlock(); 41 | sign.getChunk(); //load the chunk 42 | if (MaterialUtil.ISSIGN.get(sign)) { 43 | BlockFace facing = BlockUtil.getFacing(sign); 44 | BlockFace direction = facing; 45 | Block destinationRail = Util.getRailsFromSign(sign); 46 | if (destinationRail == null) { 47 | return; 48 | } 49 | boolean isPlate = MaterialUtil.ISPRESSUREPLATE.get(destinationRail); 50 | if (isPlate || MaterialUtil.ISRAILS.get(destinationRail)) { 51 | //rail aligned at sign? 52 | facing = FaceUtil.toRailsDirection(facing); 53 | if (isPlate || facing == BlockUtil.getRails(destinationRail).getDirection()) { 54 | //Allowed? 55 | if (!this.teleportTimes.isMarked(info.getBlock(), MyWorlds.teleportInterval)) { 56 | this.teleportTimes.mark(sign); 57 | info.getGroup().teleportAndGo(destinationRail, direction); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | @Override 66 | public boolean build(SignChangeActionEvent event) { 67 | if (event.hasRails()) { 68 | return handleBuild(event, Permission.BUILD_TELEPORTER, "train teleporter", "teleport trains large distances to another teleporter sign"); 69 | } 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionAnnounce.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.Sign; 4 | 5 | import com.bergerkiller.bukkit.tc.Permission; 6 | import com.bergerkiller.bukkit.tc.TrainCarts; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 9 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 10 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 11 | 12 | public class SignActionAnnounce extends SignAction { 13 | 14 | @Override 15 | public boolean match(SignActionEvent info) { 16 | return info.isType("announce"); 17 | } 18 | 19 | @Override 20 | public void execute(SignActionEvent info) { 21 | if (info.isTrainSign() && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON)) { 22 | if (!info.hasRailedMember() || !info.isPowered()) return; 23 | sendMessage(info, info.getGroup()); 24 | } else if (info.isCartSign() && info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON)) { 25 | if (!info.hasRailedMember() || !info.isPowered()) return; 26 | sendMessage(info, info.getMember()); 27 | } else if (info.isRCSign() && info.isAction(SignActionType.REDSTONE_ON)) { 28 | for (MinecartGroup group : info.getRCTrainGroups()) { 29 | sendMessage(info, group); 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public boolean canSupportRC() { 36 | return true; 37 | } 38 | 39 | @Override 40 | public boolean build(SignChangeActionEvent event) { 41 | if (event.getMode() != SignActionMode.NONE) { 42 | if (event.isType("announce")) { 43 | if (event.isRCSign()) { 44 | return handleBuild(event, Permission.BUILD_ANNOUNCER, "announcer", "remotely send a message to all the players in the train"); 45 | } else { 46 | return handleBuild(event, Permission.BUILD_ANNOUNCER, "announcer", "send a message to players in a train"); 47 | } 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | public static void sendMessage(SignActionEvent info, MinecartGroup group) { 54 | String msg = getMessage(info); 55 | for (MinecartMember member : group) { 56 | if (member.getEntity().hasPlayerPassenger()) { 57 | TrainCarts.sendMessage(member.getEntity().getPlayerPassenger(), msg); 58 | } 59 | } 60 | } 61 | 62 | public static void sendMessage(SignActionEvent info, MinecartMember member) { 63 | if (member.getEntity().hasPlayerPassenger()) { 64 | TrainCarts.sendMessage(member.getEntity().getPlayerPassenger(), getMessage(info)); 65 | } 66 | } 67 | 68 | public static String getMessage(SignActionEvent info) { 69 | StringBuilder message = new StringBuilder(32); 70 | message.append(info.getLine(2)); 71 | message.append(info.getLine(3)); 72 | for (Sign sign : info.findSignsBelow()) { 73 | for (String line : sign.getLines()) { 74 | message.append(line); 75 | } 76 | } 77 | return TrainCarts.getMessage(message.toString()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementMob.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import com.bergerkiller.bukkit.common.utils.EntityUtil; 4 | import com.bergerkiller.bukkit.tc.Util; 5 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 7 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 8 | 9 | public class StatementMob extends Statement { 10 | 11 | @Override 12 | public boolean match(String text) { 13 | return text.equals("mob") || text.equals("mobs"); 14 | } 15 | 16 | @Override 17 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 18 | return member.getEntity().hasPassenger() && EntityUtil.isMob(member.getEntity().getPassenger()); 19 | } 20 | 21 | @Override 22 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 23 | int count = 0; 24 | for (MinecartMember member : group) { 25 | if (member.getEntity().isVehicle() && EntityUtil.isMob(member.getEntity().getPassenger())) { 26 | count++; 27 | } 28 | } 29 | return Util.evaluate(count, text); 30 | } 31 | 32 | @Override 33 | public boolean matchArray(String text) { 34 | return text.equals("m"); 35 | } 36 | 37 | public boolean hasMob(MinecartMember member, String mob) { 38 | int idx = Util.getOperatorIndex(mob); 39 | if (idx == 0) { 40 | return false; 41 | } else if (idx > 0) { 42 | mob = mob.substring(0, idx - 1); 43 | } 44 | //contains one of the defined mobs? 45 | if (member.getEntity().hasPassenger() && EntityUtil.isMob(member.getEntity().getPassenger())) { 46 | String mobname = EntityUtil.getName(member.getEntity().getPassenger()); 47 | return mobname.contains(mob); 48 | } 49 | return false; 50 | } 51 | 52 | @Override 53 | public boolean handleArray(MinecartMember member, String[] mobs, SignActionEvent event) { 54 | if (mobs.length == 0) { 55 | return this.handle(member, null, event); 56 | } else { 57 | //contains one of the defined mobs? 58 | for (int i = 0; i < mobs.length; i++) { 59 | mobs[i] = mobs[i].replace("_", "").replace(" ", ""); 60 | } 61 | for (String mob : mobs) { 62 | if (hasMob(member, mob)) { 63 | return true; 64 | } 65 | } 66 | return false; 67 | } 68 | } 69 | 70 | @Override 71 | public boolean handleArray(MinecartGroup group, String[] mobs, SignActionEvent event) { 72 | if (mobs.length == 0) { 73 | return this.handle(group, null, event); 74 | } else { 75 | //contains one of the defined mobs? 76 | for (int i = 0; i < mobs.length; i++) { 77 | mobs[i] = mobs[i].replace("_", "").replace(" ", ""); 78 | } 79 | for (String mob : mobs) { 80 | int count = 0; 81 | for (MinecartMember member : group) { 82 | if (hasMob(member, mob)) { 83 | count++; 84 | } 85 | } 86 | if (Util.evaluate(count, mob)) { 87 | return true; 88 | } 89 | } 90 | return false; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/detector/DetectorSignPair.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions.detector; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | 7 | import org.bukkit.block.Block; 8 | 9 | import com.bergerkiller.bukkit.common.bases.IntVector3; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | import com.bergerkiller.bukkit.tc.detector.DetectorListener; 13 | import com.bergerkiller.bukkit.tc.detector.DetectorRegion; 14 | 15 | public class DetectorSignPair implements DetectorListener { 16 | 17 | public DetectorSignPair(Block sign1, Block sign2) { 18 | this.sign1 = new DetectorSign(this, sign1); 19 | this.sign2 = new DetectorSign(this, sign2); 20 | } 21 | 22 | public DetectorSignPair(IntVector3 sign1, IntVector3 sign2) { 23 | this.sign1 = new DetectorSign(this, sign1); 24 | this.sign2 = new DetectorSign(this, sign2); 25 | } 26 | 27 | public DetectorSign sign1, sign2; 28 | public DetectorRegion region; 29 | 30 | public static DetectorSignPair read(DataInputStream stream) throws IOException { 31 | IntVector3 sign1 = IntVector3.read(stream); 32 | IntVector3 sign2 = IntVector3.read(stream); 33 | DetectorSignPair detector = new DetectorSignPair(sign1, sign2); 34 | detector.sign1.wasDown = stream.readBoolean(); 35 | detector.sign2.wasDown = stream.readBoolean(); 36 | return detector; 37 | } 38 | 39 | public void write(DataOutputStream stream) throws IOException { 40 | this.sign1.getLocation().write(stream); 41 | this.sign2.getLocation().write(stream); 42 | stream.writeBoolean(this.sign1.wasDown); 43 | stream.writeBoolean(this.sign2.wasDown); 44 | } 45 | 46 | @Override 47 | public void onRegister(DetectorRegion region) { 48 | this.region = region; 49 | } 50 | 51 | @Override 52 | public void onUnregister(DetectorRegion region) { 53 | if (this.region == region) this.region = null; 54 | } 55 | 56 | @Override 57 | public void onLeave(MinecartMember member) { 58 | this.sign1.onLeave(member); 59 | this.sign2.onLeave(member); 60 | } 61 | 62 | @Override 63 | public void onEnter(MinecartMember member) { 64 | this.sign1.onEnter(member); 65 | this.sign2.onEnter(member); 66 | } 67 | 68 | @Override 69 | public void onLeave(MinecartGroup group) { 70 | this.sign1.onLeave(group); 71 | this.sign2.onLeave(group); 72 | } 73 | 74 | @Override 75 | public void onEnter(MinecartGroup group) { 76 | this.sign1.onEnter(group); 77 | this.sign2.onEnter(group); 78 | } 79 | 80 | @Override 81 | public void onUpdate(MinecartMember member) { 82 | this.sign1.onUpdate(member); 83 | this.sign2.onUpdate(member); 84 | } 85 | 86 | @Override 87 | public void onUpdate(MinecartGroup group) { 88 | this.sign1.onUpdate(group); 89 | this.sign2.onUpdate(group); 90 | } 91 | 92 | @Override 93 | public void onUnload(MinecartGroup group) { 94 | //TODO: Unloaded group storage system 95 | this.onLeave(group); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/InteractType.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedHashSet; 5 | 6 | /** 7 | * An active type of Object to interact with 8 | */ 9 | public enum InteractType { 10 | CHEST, FURNACE, DISPENSER, GROUNDITEM, DROPPER; 11 | 12 | /** 13 | * Parses all the active interactables represented by the root and name 14 | * 15 | * @param root of the active object operation (collect/deposit) 16 | * @param name of the object (textual expression) 17 | * @return A collection of InteractTypes represented 18 | */ 19 | public static Collection parse(String root, String name) { 20 | name = name.toLowerCase(); 21 | LinkedHashSet typesToCheck = new LinkedHashSet(); 22 | if (root.equals("collect")) { 23 | if (name.startsWith("chest out")) { 24 | typesToCheck.add(CHEST); 25 | } else if (name.startsWith("dispenser out")) { 26 | typesToCheck.add(DISPENSER); 27 | } else if (name.startsWith("dropper out")) { 28 | typesToCheck.add(DROPPER); 29 | } else if (name.startsWith("furnace out")) { 30 | typesToCheck.add(FURNACE); 31 | } else if (name.startsWith("pickup") || name.startsWith("pick up")) { 32 | typesToCheck.add(GROUNDITEM); 33 | } 34 | } else if (root.equals("deposit")) { 35 | if (name.startsWith("chest in")) { 36 | typesToCheck.add(CHEST); 37 | } else if (name.startsWith("dispenser in")) { 38 | typesToCheck.add(DISPENSER); 39 | } else if (name.startsWith("dropper in")) { 40 | typesToCheck.add(DROPPER); 41 | } else if (name.startsWith("furnace in")) { 42 | typesToCheck.add(FURNACE); 43 | } else if (name.startsWith("smelt")) { 44 | typesToCheck.add(FURNACE); 45 | } else if (name.startsWith("drop items") || name.startsWith("dropitems")) { 46 | typesToCheck.add(GROUNDITEM); 47 | } 48 | } 49 | if (name.startsWith(root + ' ')) { 50 | String types = name.substring(root.length() + 1).toLowerCase(); 51 | if (types.startsWith("chest")) { 52 | typesToCheck.add(CHEST); 53 | } else if (types.startsWith("furn")) { 54 | typesToCheck.add(FURNACE); 55 | } else if (types.startsWith("disp")) { 56 | typesToCheck.add(DISPENSER); 57 | } else if (types.startsWith("drop")) { 58 | typesToCheck.add(DROPPER); 59 | } else if (types.startsWith("ground")) { 60 | typesToCheck.add(GROUNDITEM); 61 | } else { 62 | for (char c : types.toCharArray()) { 63 | if (c == 'c') { 64 | typesToCheck.add(CHEST); 65 | } else if (c == 'f') { 66 | typesToCheck.add(FURNACE); 67 | } else if (c == 'd') { 68 | typesToCheck.add(DISPENSER); 69 | } else if (c == 'g') { 70 | typesToCheck.add(GROUNDITEM); 71 | } 72 | } 73 | } 74 | } 75 | if (name.startsWith(root) && typesToCheck.isEmpty()) { 76 | typesToCheck.add(CHEST); 77 | typesToCheck.add(FURNACE); 78 | typesToCheck.add(DISPENSER); 79 | typesToCheck.add(DROPPER); 80 | } 81 | return typesToCheck; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionCraft.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.World; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.block.BlockFace; 7 | import org.bukkit.inventory.Inventory; 8 | 9 | import com.bergerkiller.bukkit.common.inventory.ItemParser; 10 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 11 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 12 | import com.bergerkiller.bukkit.common.utils.RecipeUtil; 13 | import com.bergerkiller.bukkit.common.utils.WorldUtil; 14 | import com.bergerkiller.bukkit.tc.Permission; 15 | import com.bergerkiller.bukkit.tc.TrainCarts; 16 | import com.bergerkiller.bukkit.tc.Util; 17 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 18 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 19 | import com.bergerkiller.bukkit.tc.itemanimation.ItemAnimatedInventory; 20 | import com.bergerkiller.bukkit.tc.utils.TransferSignUtil; 21 | 22 | public class SignActionCraft extends SignAction { 23 | 24 | @Override 25 | public boolean match(SignActionEvent info) { 26 | return info.isType("craft"); 27 | } 28 | 29 | @Override 30 | public void execute(SignActionEvent info) { 31 | //parse the sign 32 | boolean docart = info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON) && info.isCartSign() && info.hasMember(); 33 | boolean dotrain = !docart && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON) && info.isTrainSign() && info.hasGroup(); 34 | if ((!docart && !dotrain) || !info.hasRailedMember() || !info.isPowered()) { 35 | return; 36 | } 37 | 38 | int radX, radY, radZ; 39 | radX = radY = radZ = ParseUtil.parseInt(info.getLine(1), TrainCarts.defaultTransferRadius); 40 | BlockFace dir = info.getRailDirection(); 41 | if (FaceUtil.isAlongX(dir)) { 42 | radX = 0; 43 | } else if (FaceUtil.isAlongZ(dir)) { 44 | radZ = 0; 45 | } 46 | World world = info.getWorld(); 47 | Block m = info.getRails(); 48 | Material type; 49 | Block w = null; 50 | for (int x = -radX; x <= radX && w == null; x++) { 51 | for (int y = -radY; y <= radY && w == null; y++) { 52 | for (int z = -radZ; z <= radZ && w == null; z++) { 53 | type = WorldUtil.getBlockType(world, m.getX() + x, m.getY() + y, m.getZ() + z); 54 | if (type == Material.WORKBENCH) { 55 | w = m.getRelative(x, y, z); 56 | } 57 | } 58 | } 59 | } 60 | if (w != null) { 61 | //get the inventory to transfer in 62 | Inventory inventory = TransferSignUtil.getInventory(info); 63 | if (inventory == null) { 64 | return; 65 | } 66 | 67 | if (TrainCarts.showTransferAnimations) { 68 | inventory = ItemAnimatedInventory.convert(inventory, info.getMember(), w); 69 | } 70 | 71 | // craft 72 | for (ItemParser item : Util.getParsers(info.getLine(2), info.getLine(3))) { 73 | RecipeUtil.craftItems(item, inventory); 74 | } 75 | } 76 | } 77 | 78 | @Override 79 | public boolean build(SignChangeActionEvent event) { 80 | if (event.getMode() != SignActionMode.NONE) { 81 | if (event.isType("craft")) { 82 | return handleBuild(event, Permission.BUILD_CRAFTER, "workbench item crafter", "craft items inside storage minecarts"); 83 | } 84 | } 85 | return false; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/storage/OfflineMember.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.storage; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.util.UUID; 7 | 8 | import org.bukkit.Chunk; 9 | import org.bukkit.World; 10 | import org.bukkit.entity.Entity; 11 | import org.bukkit.entity.Minecart; 12 | import org.bukkit.util.Vector; 13 | 14 | import com.bergerkiller.bukkit.common.entity.CommonEntity; 15 | import com.bergerkiller.bukkit.common.utils.EntityUtil; 16 | import com.bergerkiller.bukkit.common.utils.WorldUtil; 17 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 18 | import com.bergerkiller.bukkit.tc.controller.MinecartMemberStore; 19 | 20 | /** 21 | * Contains the information to get and restore a Minecart 22 | */ 23 | public class OfflineMember { 24 | public double motX, motZ; 25 | public UUID entityUID; 26 | public int cx, cz; 27 | public OfflineGroup group; 28 | 29 | public OfflineMember() {} 30 | public OfflineMember(OfflineGroup group, MinecartMember instance) { 31 | CommonEntity entity = instance.getEntity(); 32 | this.motX = entity.vel.getX(); 33 | this.motZ = entity.vel.getZ(); 34 | this.entityUID = entity.getUniqueId(); 35 | this.cx = entity.loc.x.chunk(); 36 | this.cz = entity.loc.z.chunk(); 37 | this.group = group; 38 | } 39 | 40 | public boolean isMoving() { 41 | return Math.abs(motX) >= CommonEntity.MIN_MOVE_SPEED || Math.abs(motZ) >= CommonEntity.MIN_MOVE_SPEED; 42 | } 43 | 44 | public void setVelocity(double velocity) { 45 | Vector vel = new Vector(this.motX, 0.0, this.motZ).normalize().multiply(velocity); 46 | this.motX = vel.getX(); 47 | this.motZ = vel.getZ(); 48 | } 49 | 50 | public MinecartMember create(World world) { 51 | MinecartMember mm = null; 52 | // first try to find it in the chunk 53 | Chunk c = world.getChunkAt(cx, cz); 54 | for (Entity e : WorldUtil.getEntities(c)) { 55 | if (e instanceof Minecart && e.getUniqueId().equals(this.entityUID)) { 56 | mm = MinecartMemberStore.convert((Minecart) e); 57 | break; 58 | } 59 | } 60 | // Try to find it in the world 61 | if (mm == null) { 62 | // Load a 5x5 chunk area around this Minecart so it can properly be found 63 | WorldUtil.loadChunks(world, this.cx, this.cz, 2); 64 | // Try to find it 65 | Entity e = EntityUtil.getEntity(world, this.entityUID); 66 | if (e instanceof Minecart) { 67 | mm = MinecartMemberStore.convert((Minecart) e); 68 | } 69 | } 70 | // Restore velocity 71 | if (mm != null) { 72 | mm.getEntity().vel.xz.set(this.motX, this.motZ); 73 | } 74 | return mm; 75 | } 76 | 77 | public void writeTo(DataOutputStream stream) throws IOException { 78 | stream.writeLong(entityUID.getMostSignificantBits()); 79 | stream.writeLong(entityUID.getLeastSignificantBits()); 80 | stream.writeDouble(motX); 81 | stream.writeDouble(motZ); 82 | stream.writeInt(cx); 83 | stream.writeInt(cz); 84 | } 85 | 86 | public static OfflineMember readFrom(DataInputStream stream) throws IOException { 87 | OfflineMember wm = new OfflineMember(); 88 | wm.entityUID = new UUID(stream.readLong(), stream.readLong()); 89 | wm.motX = stream.readDouble(); 90 | wm.motZ = stream.readDouble(); 91 | wm.cx = stream.readInt(); 92 | wm.cz = stream.readInt(); 93 | return wm; 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/type/MinecartMemberChest.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.type; 2 | 3 | import org.bukkit.Effect; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Entity; 6 | import org.bukkit.entity.Item; 7 | import org.bukkit.inventory.Inventory; 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecartChest; 11 | import com.bergerkiller.bukkit.common.inventory.ItemParser; 12 | import com.bergerkiller.bukkit.common.utils.EntityUtil; 13 | import com.bergerkiller.bukkit.common.utils.ItemUtil; 14 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 15 | import com.bergerkiller.bukkit.tc.GroupUnloadedException; 16 | import com.bergerkiller.bukkit.tc.MemberMissingException; 17 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 18 | import com.bergerkiller.bukkit.tc.controller.MinecartMemberInventory; 19 | 20 | public class MinecartMemberChest extends MinecartMember { 21 | 22 | @Override 23 | public void onAttached() { 24 | super.onAttached(); 25 | entity.setInventoryController(new MinecartMemberInventory()); 26 | } 27 | 28 | public boolean hasItem(ItemParser item) { 29 | if (item == null) 30 | return false; 31 | if (item.hasData()) { 32 | return this.hasItem(item.getType(), item.getData()); 33 | } else { 34 | return this.hasItem(item.getType()); 35 | } 36 | } 37 | 38 | public boolean hasItem(Material type, int data) { 39 | for (ItemStack stack : this.entity.getInventory()) { 40 | if (!LogicUtil.nullOrEmpty(stack)) { 41 | if (stack.getType() == type && stack.getDurability() == data) { 42 | return true; 43 | } 44 | } 45 | } 46 | return false; 47 | } 48 | 49 | public boolean hasItem(Material type) { 50 | for (ItemStack stack : this.entity.getInventory()) { 51 | if (!LogicUtil.nullOrEmpty(stack)) { 52 | if (stack.getType() == type) { 53 | return true; 54 | } 55 | } 56 | } 57 | return false; 58 | } 59 | 60 | public boolean hasItems() { 61 | for (ItemStack stack : this.entity.getInventory()) { 62 | if (stack != null) { 63 | return true; 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | @Override 70 | public void onPhysicsPostMove(double speedFactor) throws MemberMissingException, GroupUnloadedException { 71 | super.onPhysicsPostMove(speedFactor); 72 | if (this.getProperties().canPickup()) { 73 | Inventory inv = entity.getInventory(); 74 | double distance; 75 | for (Entity e : entity.getNearbyEntities(2.0)) { 76 | if (!(e instanceof Item) || EntityUtil.isIgnored(e)) { 77 | continue; 78 | } 79 | ItemStack stack = ((Item) e).getItemStack(); 80 | distance = entity.loc.distanceSquared(e); 81 | if (ItemUtil.testTransfer(stack, inv) == stack.getAmount()) { 82 | if (distance < 0.7) { 83 | ItemUtil.transfer(stack, inv, Integer.MAX_VALUE); 84 | // This.world.playNote 85 | entity.getWorld().playEffect(entity.getLocation(), Effect.CLICK1, 0); 86 | if (stack.getAmount() == 0) { 87 | e.remove(); 88 | continue; 89 | } 90 | } else { 91 | final double factor; 92 | if (distance > 1) { 93 | factor = 0.8; 94 | } else if (distance > 0.75) { 95 | factor = 0.5; 96 | } else { 97 | factor = 0.1; 98 | } 99 | this.push(e, -factor / distance); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionEject.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.util.Vector; 5 | 6 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 7 | import com.bergerkiller.bukkit.common.utils.MathUtil; 8 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 9 | import com.bergerkiller.bukkit.tc.Permission; 10 | import com.bergerkiller.bukkit.tc.Util; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | import com.bergerkiller.bukkit.tc.controller.MinecartMemberStore; 13 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 14 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 15 | 16 | public class SignActionEject extends SignAction { 17 | 18 | @Override 19 | public boolean match(SignActionEvent info) { 20 | return info.isType("eject"); 21 | } 22 | 23 | @Override 24 | public boolean click(SignActionEvent info, Player player) { 25 | MinecartMember member = MinecartMemberStore.get(player.getVehicle()); 26 | if (member == null) { 27 | return false; 28 | } 29 | info.setMember(member); 30 | eject(info); 31 | return true; 32 | } 33 | 34 | public void eject(SignActionEvent info) { 35 | final boolean hasSettings = !info.getLine(2).isEmpty() || !info.getLine(3).isEmpty(); 36 | Vector offset = new Vector(); 37 | float yaw = 0F; 38 | float pitch = 0F; 39 | if (hasSettings) { 40 | // Read the offset 41 | offset = Util.parseVector(info.getLine(2), offset); 42 | 43 | // Read the rotation 44 | String[] angletext = Util.splitBySeparator(info.getLine(3)); 45 | if (angletext.length == 2) { 46 | yaw = ParseUtil.parseFloat(angletext[0], 0.0f); 47 | pitch = ParseUtil.parseFloat(angletext[1], 0.0f); 48 | } else if (angletext.length == 1) { 49 | yaw = ParseUtil.parseFloat(angletext[0], 0.0f); 50 | } 51 | 52 | // Convert to sign-relative-space 53 | float signyawoffset = (float) FaceUtil.faceToYaw(info.getFacing().getOppositeFace()); 54 | offset = MathUtil.rotate(signyawoffset, 0F, offset); 55 | yaw += signyawoffset + 90F; 56 | } 57 | 58 | // Actually eject 59 | for (MinecartMember mm : info.getMembers()) { 60 | if (hasSettings) { 61 | mm.eject(offset, yaw, pitch); 62 | } else { 63 | mm.ejectWithOffset(); 64 | } 65 | } 66 | } 67 | 68 | @Override 69 | public void execute(SignActionEvent info) { 70 | boolean isRemote = false; 71 | if (info.isCartSign() && info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON)) { 72 | } else if (info.isTrainSign() && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON)) { 73 | } else if (info.isRCSign() && info.isAction(SignActionType.REDSTONE_ON)) { 74 | isRemote = true; 75 | } else { 76 | return; 77 | } 78 | if (isRemote || (info.hasMember() && info.isPowered())) { 79 | eject(info); 80 | } 81 | } 82 | 83 | @Override 84 | public boolean build(SignChangeActionEvent event) { 85 | if (event.getMode() != SignActionMode.NONE) { 86 | if (event.isRCSign()) { 87 | return handleBuild(event, Permission.BUILD_EJECTOR, "cart ejector", "eject the passengers of a remote train"); 88 | } else { 89 | return handleBuild(event, Permission.BUILD_EJECTOR, "cart ejector", "eject the passengers of a train"); 90 | } 91 | } 92 | return false; 93 | } 94 | 95 | @Override 96 | public boolean canSupportRC() { 97 | return true; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionTicket.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.entity.Player; 7 | 8 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 9 | import com.bergerkiller.bukkit.tc.Localization; 10 | import com.bergerkiller.bukkit.tc.Permission; 11 | import com.bergerkiller.bukkit.tc.TrainCarts; 12 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 13 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 14 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 15 | import com.earth2me.essentials.register.payment.*; 16 | import com.earth2me.essentials.register.payment.Method.MethodAccount; 17 | 18 | import static com.bergerkiller.bukkit.tc.TrainCarts.getCurrencyText; 19 | 20 | /** 21 | * @author reeZZer 22 | * Me (Bergerkiller) gives a big thank-you to him for writing the economics for this feature :) 23 | */ 24 | public class SignActionTicket extends SignAction { 25 | 26 | @Override 27 | public boolean match(SignActionEvent info) { 28 | return TrainCarts.EssentialsEnabled && info.isType("ticket"); 29 | } 30 | 31 | @Override 32 | public void execute(SignActionEvent info) { 33 | final boolean isTrain; 34 | if (info.isCartSign() && info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON)) { 35 | isTrain = false; 36 | } else if (info.isTrainSign() && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON)) { 37 | isTrain = true; 38 | } else { 39 | return; 40 | } 41 | if ((info.hasMember() && info.isPowered())) { 42 | Method method = Methods.hasMethod() ? Methods.getMethod() : null; 43 | if (method != null) { 44 | double money; 45 | if (info.getLine(3).isEmpty()) { 46 | money = 30.0; 47 | } else { 48 | money = ParseUtil.parseDouble(info.getLine(3), 0.0); 49 | } 50 | final String mode = info.getLine(2); 51 | List> members; 52 | if (isTrain) { 53 | members = info.getGroup(); 54 | } else { 55 | members = new ArrayList>(1); 56 | members.add(info.getMember()); 57 | } 58 | for (MinecartMember member : members) { 59 | if (!member.getEntity().hasPlayerPassenger()) { 60 | continue; 61 | } 62 | Player player = member.getEntity().getPlayerPassenger(); 63 | if (!method.hasAccount(player.getName())) { 64 | continue; 65 | } 66 | //actually perform something with it here 67 | MethodAccount account = method.getAccount(player.getName()); 68 | 69 | if (mode.equalsIgnoreCase("add")) { 70 | account.add(money); 71 | Localization.TICKET_ADD.message(player, getCurrencyText(money)); 72 | } else if (mode.equalsIgnoreCase("check")) { 73 | Localization.TICKET_CHECK.message(player, getCurrencyText(account.balance())); 74 | } else if (mode.equalsIgnoreCase("buy")) { 75 | if (account.hasUnder(money)) { 76 | Localization.TICKET_BUYFAIL.message(player, getCurrencyText(money)); 77 | member.eject(); 78 | } else { 79 | account.subtract(money); 80 | Localization.TICKET_BUY.message(player, getCurrencyText(money)); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | public boolean build(SignChangeActionEvent event) { 90 | if (event.getMode() != SignActionMode.NONE) { 91 | return handleBuild(event, Permission.BUILD_TICKET, "ticket system", "charges the passengers of a train"); 92 | } 93 | return false; 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/rails/type/RailTypeHorizontal.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.rails.type; 2 | 3 | import org.bukkit.World; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.common.bases.IntVector3; 8 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 9 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 10 | import com.bergerkiller.bukkit.tc.Util; 11 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 12 | 13 | public abstract class RailTypeHorizontal extends RailType { 14 | 15 | @Override 16 | public IntVector3 findRail(MinecartMember member, World world, IntVector3 pos) { 17 | // Try to find the rail at the current position or one below 18 | if (isRail(world, pos.x, pos.y, pos.z)) { 19 | return pos; 20 | } 21 | if (isRail(world, pos.x, pos.y - 1, pos.z)) { 22 | return pos.add(BlockFace.DOWN); 23 | } 24 | return null; 25 | } 26 | 27 | @Override 28 | public Block findMinecartPos(Block trackBlock) { 29 | return trackBlock; 30 | } 31 | 32 | @Override 33 | public boolean onBlockCollision(MinecartMember member, Block railsBlock, Block hitBlock, BlockFace hitFace) { 34 | if (!super.onBlockCollision(member, railsBlock, hitBlock, hitFace)) { 35 | return false; 36 | } 37 | // Handle collision (ignore UP/DOWN, recalculate hitFace for this) 38 | Block posBlock = findMinecartPos(railsBlock); 39 | hitFace = FaceUtil.getDirection(hitBlock, posBlock, false); 40 | final BlockFace hitToFace = hitFace.getOppositeFace(); 41 | if (posBlock.getY() == hitBlock.getY()) { 42 | // If the hit face is not a valid direction to go to, ignore it 43 | int dx = hitBlock.getX() - posBlock.getX(); 44 | int dz = hitBlock.getZ() - posBlock.getZ(); 45 | if (Math.abs(dx) > 0 && Math.abs(dz) > 0) { 46 | // CANCEL: we hit a corner block 47 | return false; 48 | } 49 | BlockFace[] possible = this.getPossibleDirections(railsBlock); 50 | if (!LogicUtil.contains(hitToFace, possible)) { 51 | // CANCEL: we hit a block that is not an end-direction 52 | return false; 53 | } 54 | } 55 | if (member.isOnSlope()) { 56 | // Cancel collisions with blocks two above this sloped rail 57 | if (hitBlock.getX() == posBlock.getX() && hitBlock.getZ() == posBlock.getZ()) { 58 | int dy = hitBlock.getY() - posBlock.getY(); 59 | if (dy >= 2) { 60 | return false; 61 | } 62 | } 63 | 64 | // Cancel collisions with blocks at the heading of sloped rails when going up vertically 65 | BlockFace railDirection = this.getDirection(railsBlock); 66 | if (hitToFace == railDirection && Util.isVerticalAbove(posBlock, railDirection)) { 67 | return false; 68 | } 69 | 70 | // Cancel collisions with blocks 'right above' the next rail when going down the slope 71 | IntVector3 diff = new IntVector3(hitBlock).subtract(posBlock.getX(), posBlock.getY(), posBlock.getZ()); 72 | if (diff.x == hitToFace.getModX() && diff.z == hitToFace.getModZ() && 73 | (diff.y > 1 || (diff.y == 1 && railDirection != hitToFace))) { 74 | return false; 75 | } 76 | } 77 | return true; 78 | } 79 | 80 | @Override 81 | public BlockFace getSignColumnDirection(Block railsBlock) { 82 | return BlockFace.DOWN; 83 | } 84 | 85 | @Override 86 | public Block findRail(Block pos) { 87 | // Try to find the rail at the current position or one below 88 | if (isRail(pos)) { 89 | return pos; 90 | } 91 | if (isRail(pos, BlockFace.DOWN)) { 92 | return pos.getRelative(BlockFace.DOWN); 93 | } 94 | return null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionEffect.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 4 | import com.bergerkiller.bukkit.common.utils.StringUtil; 5 | import com.bergerkiller.bukkit.tc.Permission; 6 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 7 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 8 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 9 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 10 | import com.bergerkiller.bukkit.tc.utils.Effect; 11 | 12 | public class SignActionEffect extends SignAction { 13 | 14 | @Override 15 | public boolean match(SignActionEvent info) { 16 | return info.isType("effect", "meffect"); 17 | } 18 | 19 | @Override 20 | public void execute(SignActionEvent info) { 21 | boolean move = info.isType("meffect"); 22 | if (!info.isPowered()) return; 23 | Effect eff = parse(info); 24 | if (info.isAction(SignActionType.MEMBER_MOVE)) { 25 | if (move) { 26 | if (info.isTrainSign()) { 27 | for (MinecartMember member : info.getGroup()) { 28 | eff.play(member.getEntity().getLocation()); 29 | } 30 | } else if (info.isCartSign()) { 31 | eff.play(info.getMember().getEntity().getLocation()); 32 | } 33 | } 34 | return; 35 | } 36 | if (info.isTrainSign() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.GROUP_ENTER) && info.hasGroup()) { 37 | for (MinecartMember member : info.getGroup()) { 38 | eff.play(member.getEntity().getLocation()); 39 | } 40 | } else if (info.isCartSign() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.MEMBER_ENTER) && info.hasMember()) { 41 | eff.play(info.getMember().getEntity().getLocation()); 42 | } else if (info.isRCSign() && info.isAction(SignActionType.REDSTONE_ON)) { 43 | for (MinecartGroup group : info.getRCTrainGroups()) { 44 | for (MinecartMember member : group) { 45 | eff.play(member.getEntity().getLocation()); 46 | } 47 | } 48 | } else if (info.isAction(SignActionType.REDSTONE_ON)) { 49 | if (info.hasRails()) { 50 | eff.play(info.getCenterLocation()); 51 | } else { 52 | eff.play(info.getLocation().add(0.0, 2.0, 0.0)); 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | public boolean build(SignChangeActionEvent event) { 59 | String app = event.isType("meffect") ? " while moving" : ""; 60 | if (event.isCartSign()) { 61 | return handleBuild(event, Permission.BUILD_EFFECT, "cart effect player", "play an effect in the minecart" + app); 62 | } else if (event.isTrainSign()) { 63 | return handleBuild(event, Permission.BUILD_EFFECT, "train effect player", "play an effect in all minecarts of the train" + app); 64 | } else if (event.isRCSign()) { 65 | return handleBuild(event, Permission.BUILD_EFFECT, "train effect player", "play an effect in all minecarts of the train" + app); 66 | } 67 | return false; 68 | } 69 | 70 | @Override 71 | public boolean canSupportRC() { 72 | return true; 73 | } 74 | 75 | public static Effect parse(SignActionEvent event) { 76 | Effect eff = new Effect(); 77 | eff.parseEffect(event.getLine(2)); 78 | eff.parseEffect(event.getLine(3)); 79 | String[] args = StringUtil.getAfter(event.getLine(1), " ").trim().split(" ", -1); 80 | try { 81 | if (args.length >= 1) { 82 | eff.pitch = (float) ParseUtil.parseDouble(args[0], 1.0); 83 | } 84 | if (args.length == 2) { 85 | eff.volume = (float) ParseUtil.parseDouble(args[1], 1.0); 86 | } 87 | } catch (NumberFormatException ex) {} 88 | return eff; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/utils/GroundItemsInventory.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | import org.bukkit.Location; 8 | import org.bukkit.block.Block; 9 | import org.bukkit.entity.Item; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.util.Vector; 12 | 13 | import com.bergerkiller.bukkit.common.inventory.InventoryBase; 14 | import com.bergerkiller.bukkit.common.utils.EntityUtil; 15 | import com.bergerkiller.bukkit.common.utils.ItemUtil; 16 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 17 | import com.bergerkiller.bukkit.common.utils.WorldUtil; 18 | 19 | /** 20 | * Allows you to use items on the ground as an Inventory
21 | * Is of a dynamic size; the last item is always null
22 | * If this item is set, a new item is spawned 23 | */ 24 | public class GroundItemsInventory extends InventoryBase { 25 | private final List items = new ArrayList(); 26 | private final Location location; 27 | 28 | public GroundItemsInventory(Block block, double range) { 29 | this(block.getLocation().add(0.5, 0.5, 0.5), range); 30 | } 31 | 32 | public GroundItemsInventory(Location location, double range) { 33 | this.location = location; 34 | double rangeSquared = range * range; 35 | for (org.bukkit.entity.Entity e : WorldUtil.getEntities(location.getWorld())) { 36 | if (e instanceof Item && e.getLocation().distanceSquared(location) <= rangeSquared) { 37 | this.items.add((Item) e); 38 | } 39 | } 40 | } 41 | 42 | @Override 43 | public int getSize() { 44 | return this.items.size() + 1; 45 | } 46 | 47 | /** 48 | * Gets the Location of the center of this ground items cluster 49 | * 50 | * @return ground center location 51 | */ 52 | public Location getLocation() { 53 | return this.location; 54 | } 55 | 56 | /** 57 | * Gets the item at the index specified
58 | * Note that the last element has no item! 59 | * 60 | * @param index to get the item at 61 | * @return the item 62 | */ 63 | public Item getEntity(int index) { 64 | return this.items.get(index); 65 | } 66 | 67 | @Override 68 | public void setItem(int index, ItemStack stack) { 69 | if (index == this.items.size()) { 70 | if (!LogicUtil.nullOrEmpty(stack)) { 71 | // Spawn new item for this item stack 72 | Random random = WorldUtil.getRandom(this.location.getWorld()); 73 | Location spawnLoc = this.location.clone().add(-0.45, -0.45, -0.45); 74 | spawnLoc = spawnLoc.add(0.9f * random.nextFloat(), 0.9f * random.nextFloat(), 0.9f * random.nextFloat()); 75 | Item item = location.getWorld().dropItem(spawnLoc, stack); 76 | item.setVelocity(new Vector(0, 0, 0)); 77 | this.items.add(item); 78 | } 79 | } else { 80 | // Set item stack, if null, kill the item 81 | Item item = this.items.get(index); 82 | EntityUtil.setDead(item, LogicUtil.nullOrEmpty(stack)); 83 | if (!item.isDead()) { 84 | item.setItemStack(stack); 85 | this.items.set(index, ItemUtil.respawnItem(item)); 86 | } 87 | } 88 | } 89 | 90 | @Override 91 | public ItemStack getItem(int index) { 92 | if (index == this.items.size()) { 93 | return null; 94 | } else { 95 | Item item = this.items.get(index); 96 | if (item.isDead()) { 97 | return null; 98 | } else { 99 | return item.getItemStack(); 100 | } 101 | } 102 | } 103 | 104 | @Override 105 | public String getName() { 106 | return "Ground Items"; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionBlockChanger.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.bergerkiller.bukkit.common.entity.type.CommonMinecart; 9 | import com.bergerkiller.bukkit.common.inventory.ItemParser; 10 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 11 | import com.bergerkiller.bukkit.tc.Permission; 12 | import com.bergerkiller.bukkit.tc.Util; 13 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 14 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 15 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 16 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 17 | 18 | public class SignActionBlockChanger extends SignAction { 19 | private static final int BLOCK_OFFSET_NONE = Integer.MAX_VALUE; 20 | 21 | @Override 22 | public boolean match(SignActionEvent info) { 23 | return info.isType("blockchanger", "setblock", "changeblock"); 24 | } 25 | 26 | @Override 27 | public void execute(SignActionEvent info) { 28 | if (!info.isPowered()) { 29 | return; 30 | } 31 | ItemParser[] blocks = Util.getParsers(info.getLine(2), info.getLine(3)); 32 | int blockOffset = ParseUtil.parseInt(info.getLine(1), BLOCK_OFFSET_NONE); 33 | if (info.isTrainSign() && info.hasGroup() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.GROUP_ENTER)) { 34 | setBlocks(info.getGroup(), blocks, blockOffset); 35 | } else if (info.isCartSign() && info.hasMember() && info.isAction(SignActionType.REDSTONE_ON, SignActionType.MEMBER_ENTER)) { 36 | List> tmp = new ArrayList>(1); 37 | tmp.add(info.getMember()); 38 | setBlocks(tmp, blocks, blockOffset); 39 | } else if (info.isRCSign() && info.isAction(SignActionType.REDSTONE_ON)) { 40 | for (MinecartGroup group : info.getRCTrainGroups()) { 41 | setBlocks(group, blocks, blockOffset); 42 | } 43 | } else { 44 | return; 45 | } 46 | } 47 | 48 | @Override 49 | public boolean build(SignChangeActionEvent event) { 50 | if (event.isCartSign()) { 51 | return handleBuild(event, Permission.BUILD_BLOCKCHANGER, "cart block changer", "change the block displayed in a minecart"); 52 | } else if (event.isTrainSign()) { 53 | return handleBuild(event, Permission.BUILD_BLOCKCHANGER, "train block changer", "change the blocks displayed in a train"); 54 | } else if (event.isRCSign()) { 55 | return handleBuild(event, Permission.BUILD_BLOCKCHANGER, "train block changer", "change the blocks displayed in a train remotely"); 56 | } 57 | return false; 58 | } 59 | 60 | @Override 61 | public boolean canSupportRC() { 62 | return true; 63 | } 64 | 65 | public static void setBlocks(Collection> members, String blocksText) { 66 | setBlocks(members, Util.getParsers(blocksText), BLOCK_OFFSET_NONE); 67 | } 68 | 69 | public static void setBlocks(Collection> members, ItemParser[] blocks, int blockOffset) { 70 | Iterator> iter = members.iterator(); 71 | while (true) { 72 | for (ItemParser block : blocks) { 73 | final int amount = block.hasAmount() ? block.getAmount() : 1; 74 | for (int i = 0; i < amount; i++) { 75 | if (!iter.hasNext()) { 76 | return; 77 | } 78 | CommonMinecart entity = iter.next().getEntity(); 79 | entity.setBlock(block.getType(), block.getData()); 80 | if (blockOffset != BLOCK_OFFSET_NONE) { 81 | entity.setBlockOffset(blockOffset); 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.bergerkiller.bukkit 6 | TrainCarts 7 | 1.73.1-SNAPSHOT 8 | jar 9 | 10 | TrainCarts 11 | http://dev.bukkit.org/server-mods/traincarts/ 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | 20 | bukkit-repo 21 | http://repo.bukkit.org/content/groups/public 22 | 23 | 24 | 25 | 26 | 27 | org.bukkit 28 | bukkit 29 | 1.7.2-R0.1-SNAPSHOT 30 | system 31 | ${project.basedir}/lib/bukkit-1.7.2-R0.4-20140216.011848-2.jar 32 | true 33 | 34 | 35 | com.bergerkiller.bukkit 36 | MyWorlds 37 | 1.67 38 | system 39 | ${project.basedir}/lib/MyWorlds-1.67.jar 40 | true 41 | 42 | 43 | com.earth2me 44 | essentials 45 | 2.10.1 46 | system 47 | ${project.basedir}/lib/Essentials.jar 48 | true 49 | 50 | 51 | com.bergerkiller.bukkit 52 | SignLink 53 | 1.34 54 | system 55 | ${project.basedir}/lib/SignLink-1.34.jar 56 | true 57 | 58 | 59 | com.bergerkiller.bukkit 60 | BKCommonLib 61 | 1.59-SNAPSHOT 62 | provided 63 | 64 | 65 | junit 66 | junit 67 | 3.8.1 68 | test 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | src/main/java 78 | true 79 | 80 | plugin.yml 81 | 82 | 83 | 84 | clean install 85 | 86 | 87 | 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-compiler-plugin 92 | 2.4 93 | 94 | 1.6 95 | 1.6 96 | true 97 | true 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/ActionTrackerMember.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.BlockFace; 5 | import org.bukkit.util.Vector; 6 | 7 | import com.bergerkiller.bukkit.tc.actions.Action; 8 | import com.bergerkiller.bukkit.tc.actions.MemberAction; 9 | import com.bergerkiller.bukkit.tc.actions.MemberActionLaunch; 10 | import com.bergerkiller.bukkit.tc.actions.MemberActionLaunchDirection; 11 | import com.bergerkiller.bukkit.tc.actions.MemberActionLaunchLocation; 12 | import com.bergerkiller.bukkit.tc.actions.MemberActionWaitDistance; 13 | import com.bergerkiller.bukkit.tc.actions.MemberActionWaitLocation; 14 | import com.bergerkiller.bukkit.tc.actions.MemberActionWaitOccupied; 15 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 16 | 17 | /** 18 | * An Action tracker meant for a group Member. 19 | * Some adding methods add the action to the group instead of the member. 20 | */ 21 | public class ActionTrackerMember extends ActionTracker { 22 | private final MinecartMember owner; 23 | 24 | public ActionTrackerMember(MinecartMember owner) { 25 | this.owner = owner; 26 | } 27 | 28 | /** 29 | * Gets the owner of this Block Tracker 30 | * 31 | * @return the Owner 32 | */ 33 | public MinecartMember getOwner() { 34 | return owner; 35 | } 36 | 37 | @Override 38 | public void clear() { 39 | super.clear(); 40 | owner.getGroup().getActions().removeActions(owner); 41 | } 42 | 43 | @Override 44 | public T addAction(T action) { 45 | if (action instanceof MemberAction) { 46 | ((MemberAction) action).setMember(owner); 47 | } 48 | return super.addAction(action); 49 | } 50 | 51 | /** 52 | * Adds a Member Action (for this member) to the group action scheduler 53 | * 54 | * @param action to add 55 | * @return the action added 56 | */ 57 | public A addGroupAction(A action) { 58 | action.setMember(owner); 59 | return owner.getGroup().getActions().addAction(action); 60 | } 61 | 62 | public MemberActionWaitDistance addActionWaitDistance(double distance) { 63 | return addGroupAction(new MemberActionWaitDistance(distance)); 64 | } 65 | 66 | public MemberActionWaitLocation addActionWaitLocation(Location location) { 67 | return addGroupAction(new MemberActionWaitLocation(location)); 68 | } 69 | 70 | public MemberActionWaitLocation addActionWaitLocation(Location location, double radius) { 71 | return addGroupAction(new MemberActionWaitLocation(location, radius)); 72 | } 73 | 74 | public MemberActionLaunch addActionLaunch(double distance, double targetvelocity) { 75 | return addGroupAction(new MemberActionLaunch(distance, targetvelocity)); 76 | } 77 | 78 | public MemberActionLaunchLocation addActionLaunch(Location destination, double targetvelocity) { 79 | return addGroupAction(new MemberActionLaunchLocation(targetvelocity, destination)); 80 | } 81 | 82 | public MemberActionLaunchLocation addActionLaunch(Vector offset, double targetvelocity) { 83 | return addActionLaunch(owner.getEntity().getLocation().add(offset), targetvelocity); 84 | } 85 | 86 | public MemberActionLaunchDirection addActionLaunch(final BlockFace direction, double targetdistance, double targetvelocity) { 87 | return addGroupAction(new MemberActionLaunchDirection(targetdistance, targetvelocity, direction)); 88 | } 89 | 90 | public MemberActionWaitOccupied addActionWaitOccupied(int maxsize, long launchDelay, double launchDistance) { 91 | return addGroupAction(new MemberActionWaitOccupied(maxsize, launchDelay, launchDistance)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/statements/StatementItems.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.statements; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | import com.bergerkiller.bukkit.common.inventory.ItemParser; 7 | import com.bergerkiller.bukkit.common.utils.ItemUtil; 8 | import com.bergerkiller.bukkit.tc.Util; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 10 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 11 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberChest; 12 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 13 | 14 | public class StatementItems extends Statement { 15 | 16 | @Override 17 | public boolean match(String text) { 18 | return text.startsWith("items"); 19 | } 20 | 21 | @Override 22 | public boolean handle(MinecartMember member, String text, SignActionEvent event) { 23 | final Inventory inventory = getInventory(member); 24 | if (inventory == null) { 25 | return false; 26 | } 27 | int count = ItemUtil.getItemCount(getInventory(member), -1, -1); 28 | return Util.evaluate(count, text); 29 | } 30 | 31 | @Override 32 | public boolean handle(MinecartGroup group, String text, SignActionEvent event) { 33 | final Inventory inventory = getInventory(group); 34 | if (inventory == null) { 35 | return false; 36 | } 37 | int count = ItemUtil.getItemCount(inventory, -1, -1); 38 | return Util.evaluate(count, text); 39 | } 40 | 41 | @Override 42 | public boolean matchArray(String text) { 43 | return text.equals("i"); 44 | } 45 | 46 | public boolean handleInventory(Inventory inv, String[] items) { 47 | if (inv == null) { 48 | return false; 49 | } 50 | int opidx; 51 | int count; 52 | for (String itemname : items) { 53 | opidx = Util.getOperatorIndex(itemname); 54 | String itemnamefixed; 55 | if (opidx > 0) { 56 | itemnamefixed = itemname.substring(0, opidx); 57 | } else { 58 | itemnamefixed = itemname; 59 | } 60 | for (ItemParser parser : Util.getParsers(itemnamefixed)) { 61 | count = ItemUtil.getItemCount(inv, parser.getTypeId(), parser.getData()); 62 | if (opidx == -1) { 63 | if (parser.hasAmount()) { 64 | if (count >= parser.getAmount()) { 65 | return true; 66 | } 67 | } else if (count > 0) { 68 | return true; 69 | } 70 | } else if (Util.evaluate(count, itemname)) { 71 | return true; 72 | } 73 | } 74 | // Check for 'special' named items 75 | count = 0; 76 | for (ItemStack item : inv) { 77 | if (item != null && ItemUtil.hasDisplayName(item) && ItemUtil.getDisplayName(item).equals(itemnamefixed)) { 78 | count += item.getAmount(); 79 | } 80 | } 81 | if (Util.evaluate(count, itemname)) { 82 | return true; 83 | } 84 | } 85 | return false; 86 | } 87 | 88 | public Inventory getInventory(MinecartMember member) { 89 | if (member instanceof MinecartMemberChest) { 90 | return ((MinecartMemberChest) member).getEntity().getInventory(); 91 | } else { 92 | return null; 93 | } 94 | } 95 | 96 | public Inventory getInventory(MinecartGroup group) { 97 | return group.getInventory(); 98 | } 99 | 100 | @Override 101 | public boolean handleArray(MinecartMember member, String[] items, SignActionEvent event) { 102 | return handleInventory(getInventory(member), items); 103 | } 104 | 105 | @Override 106 | public boolean handleArray(MinecartGroup group, String[] items, SignActionEvent event) { 107 | return handleInventory(getInventory(group), items); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/properties/CartPropertiesStore.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.properties; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.UUID; 6 | 7 | import org.bukkit.entity.Player; 8 | 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | 11 | /** 12 | * Stores all the Cart Properties available by Minecart UUID 13 | */ 14 | public class CartPropertiesStore { 15 | private static HashMap properties = new HashMap(); 16 | protected static HashMap editing = new HashMap(); 17 | 18 | /** 19 | * Gets the properties of the Minecart the specified player is currently editing 20 | * 21 | * @param player 22 | * @return the Cart Properties the player is editing 23 | */ 24 | public static CartProperties getEditing(Player player) { 25 | return getEditing(player.getName()); 26 | } 27 | 28 | /** 29 | * Gets the properties of the Minecart the specified player is currently editing 30 | * 31 | * @param playername of the player 32 | * @return the Cart Properties the player is editing 33 | */ 34 | public static CartProperties getEditing(String playername) { 35 | return editing.get(playername.toLowerCase()); 36 | } 37 | 38 | /** 39 | * Sets the properties of the Minecart the specified player is currently editing 40 | * 41 | * @param player 42 | * @param properties to set to 43 | */ 44 | public static void setEditing(Player player, CartProperties properties) { 45 | setEditing(player.getName(), properties); 46 | } 47 | 48 | /** 49 | * Sets the properties of the Minecart the specified player is currently editing 50 | * 51 | * @param playername of the player 52 | * @param properties to set to 53 | */ 54 | public static void setEditing(String playername, CartProperties properties) { 55 | if (properties == null) { 56 | editing.remove(playername.toLowerCase()); 57 | } else { 58 | editing.put(playername.toLowerCase(), properties); 59 | } 60 | } 61 | 62 | /** 63 | * Removes the CartProperties for the Minecart specified 64 | * 65 | * @param uuid of the Minecart 66 | */ 67 | public static void remove(UUID uuid) { 68 | CartProperties prop = properties.remove(uuid); 69 | if (prop != null) { 70 | Iterator iter = editing.values().iterator(); 71 | while (iter.hasNext()) { 72 | if (iter.next() == prop) { 73 | iter.remove(); 74 | } 75 | } 76 | TrainProperties tprop = prop.getTrainProperties(); 77 | if (tprop.contains(prop)) { 78 | tprop.remove(prop); 79 | } 80 | } 81 | } 82 | 83 | protected static void clearAllCarts() { 84 | properties.clear(); 85 | editing.clear(); 86 | } 87 | 88 | /** 89 | * Gets the Cart Properties of the Minecart specified
90 | * Constructs a new entry if none is contained. 91 | * 92 | * @param uuid of the Minecart 93 | * @param train to link the Minecart to if not contained 94 | * @return The CartProperties for the Minecart 95 | */ 96 | public static CartProperties get(UUID uuid, TrainProperties train) { 97 | CartProperties prop = properties.get(uuid); 98 | if (prop == null) { 99 | prop = new CartProperties(uuid, train); 100 | properties.put(uuid, prop); 101 | } 102 | return prop; 103 | } 104 | 105 | /** 106 | * Gets the Cart Properties of the Minecart specified 107 | * 108 | * @param member the properties belong to 109 | * @return the Cart Properties for the Minecart 110 | */ 111 | public static CartProperties get(MinecartMember member) { 112 | return get(member.getEntity().getUniqueId(), member.isUnloaded() ? null : member.getGroup().getProperties()); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionFuel.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.Material; 7 | import org.bukkit.block.BlockState; 8 | import org.bukkit.block.Chest; 9 | import org.bukkit.inventory.Inventory; 10 | import org.bukkit.inventory.ItemStack; 11 | 12 | import com.bergerkiller.bukkit.common.utils.ItemUtil; 13 | import com.bergerkiller.bukkit.common.utils.LogicUtil; 14 | import com.bergerkiller.bukkit.common.utils.ParseUtil; 15 | import com.bergerkiller.bukkit.tc.Permission; 16 | import com.bergerkiller.bukkit.tc.TrainCarts; 17 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 18 | import com.bergerkiller.bukkit.tc.controller.type.MinecartMemberFurnace; 19 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 20 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 21 | import com.bergerkiller.bukkit.tc.itemanimation.ItemAnimation; 22 | import com.bergerkiller.bukkit.tc.utils.TransferSignUtil; 23 | 24 | public class SignActionFuel extends SignAction { 25 | 26 | @Override 27 | public boolean match(SignActionEvent info) { 28 | return info.isType("fuel"); 29 | } 30 | 31 | @Override 32 | public void execute(SignActionEvent info) { 33 | if (!info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON, SignActionType.GROUP_ENTER)) { 34 | return; 35 | } 36 | //parse the sign 37 | boolean docart = info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON) && info.isCartSign() && info.hasMember(); 38 | boolean dotrain = !docart && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON) && info.isTrainSign() && info.hasGroup(); 39 | if (!docart && !dotrain) return; 40 | if (!info.isPowered()) return; 41 | 42 | //get nearby chests 43 | int radius = ParseUtil.parseInt(info.getLine(1), TrainCarts.defaultTransferRadius); 44 | List chests = new ArrayList(); 45 | for (BlockState state : TransferSignUtil.getBlockStates(info, radius, radius)) { 46 | if (state instanceof Chest) { 47 | chests.add((Chest) state); 48 | } 49 | } 50 | if (chests.isEmpty()) { 51 | return; 52 | } 53 | 54 | List> carts; 55 | if (dotrain) { 56 | carts = info.getGroup(); 57 | } else { 58 | carts = new ArrayList>(1); 59 | carts.add(info.getMember()); 60 | } 61 | 62 | int i; 63 | boolean found = false; 64 | for (MinecartMember cart : carts) { 65 | if (!(cart instanceof MinecartMemberFurnace)) { 66 | continue; 67 | } 68 | MinecartMemberFurnace member = (MinecartMemberFurnace) cart; 69 | if (!member.getEntity().hasFuel()) { 70 | found = false; 71 | for (Chest chest : chests) { 72 | Inventory inv = chest.getInventory(); 73 | for (i = 0; i < inv.getSize(); i++) { 74 | org.bukkit.inventory.ItemStack item = inv.getItem(i); 75 | if (!LogicUtil.nullOrEmpty(item) && item.getType() == Material.COAL) { 76 | ItemUtil.subtractAmount(item, 1); 77 | inv.setItem(i, item); 78 | found = true; 79 | member.addFuelTicks(3600); 80 | if (TrainCarts.showTransferAnimations) { 81 | ItemAnimation.start(chest, member, new ItemStack(Material.COAL, 1)); 82 | } 83 | break; 84 | } 85 | } 86 | if (found){ 87 | break; 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | @Override 95 | public boolean build(SignChangeActionEvent event) { 96 | if (event.getMode() != SignActionMode.NONE) { 97 | return handleBuild(event, Permission.BUILD_COLLECTOR, "powered minecart coal collector", "fuel the powered minecart using coal from a chest"); 98 | } 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/signactions/SignActionStation.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.signactions; 2 | 3 | import org.bukkit.block.BlockFace; 4 | 5 | import com.bergerkiller.bukkit.tc.Permission; 6 | import com.bergerkiller.bukkit.tc.Direction; 7 | import com.bergerkiller.bukkit.tc.Station; 8 | import com.bergerkiller.bukkit.tc.controller.MinecartGroup; 9 | import com.bergerkiller.bukkit.tc.controller.MinecartMember; 10 | import com.bergerkiller.bukkit.tc.events.SignActionEvent; 11 | import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; 12 | 13 | public class SignActionStation extends SignAction { 14 | 15 | @Override 16 | public boolean match(SignActionEvent info) { 17 | return info.isType("station") && info.getMode() != SignActionMode.NONE; 18 | } 19 | 20 | @Override 21 | public void execute(SignActionEvent info) { 22 | if (!info.isAction(SignActionType.REDSTONE_CHANGE, SignActionType.GROUP_ENTER, SignActionType.GROUP_LEAVE)) { 23 | return; 24 | } 25 | if (info.isAction(SignActionType.GROUP_LEAVE)) { 26 | if (info.getGroup().getActions().isWaitAction()) { 27 | info.getGroup().getActions().clear(); 28 | } 29 | info.setLevers(false); 30 | return; 31 | } 32 | if (!info.hasRails() || !info.hasGroup() || info.getGroup().isEmpty()) { 33 | return; 34 | } 35 | //Check if not already targeting 36 | MinecartGroup group = info.getGroup(); 37 | Station station = new Station(info); 38 | if (!station.isValid()) { 39 | return; 40 | } 41 | 42 | //What do we do? 43 | if (station.getInstruction() == null) { 44 | // Clear actions, but only if requested to do so because of a redstone change 45 | if (info.isAction(SignActionType.REDSTONE_CHANGE)) { 46 | info.getGroup().getActions().clear(); 47 | } 48 | } else if (station.getInstruction() == BlockFace.SELF) { 49 | MinecartMember centerMember = station.getCenterCart(); 50 | // Do not allow redstone changes to center a launching train 51 | if (info.isAction(SignActionType.REDSTONE_CHANGE) && (centerMember.isMovementControlled() || info.getGroup().isMoving())) { 52 | return; 53 | } 54 | 55 | //Brake 56 | //TODO: ADD CHECK?! 57 | group.getActions().clear(); 58 | BlockFace trainDirection = station.getNextDirection().getDirection(info.getFacing(), info.getMember().getDirection()); 59 | if (station.getNextDirection() != Direction.NONE) { 60 | // Actual launching here 61 | if (station.hasDelay()) { 62 | station.centerTrain(); 63 | station.waitTrain(station.getDelay()); 64 | } else if (!info.getMember().isDirectionTo(trainDirection)) { 65 | // Order the train to center prior to launching again 66 | station.centerTrain(); 67 | } 68 | station.launchTo(trainDirection, station.getLength()); 69 | } else { 70 | station.centerTrain(); 71 | station.waitTrain(Long.MAX_VALUE); 72 | } 73 | } else { 74 | //Launch 75 | group.getActions().clear(); 76 | MinecartMember head = group.head(); 77 | 78 | if (station.hasDelay() || (head.isMoving() && !info.getMember().isDirectionTo(station.getInstruction()))) { 79 | //Reversing or has delay, need to center it in the middle first 80 | station.centerTrain(); 81 | } 82 | if (station.hasDelay()) { 83 | station.waitTrain(station.getDelay()); 84 | } 85 | station.launchTo(station.getInstruction(), station.getLength()); 86 | } 87 | } 88 | 89 | @Override 90 | public boolean build(SignChangeActionEvent event) { 91 | if (event.getMode() != SignActionMode.NONE) { 92 | return handleBuild(event, Permission.BUILD_STATION, "station", "stop, wait and launch trains"); 93 | } 94 | return false; 95 | } 96 | 97 | @Override 98 | public boolean overrideFacing() { 99 | return true; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/Direction.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc; 2 | 3 | import java.util.LinkedHashSet; 4 | 5 | import org.bukkit.block.BlockFace; 6 | 7 | import com.bergerkiller.bukkit.common.utils.FaceUtil; 8 | 9 | public enum Direction { 10 | NORTH("n", "north"), EAST("e", "east"), SOUTH("s", "south"), 11 | WEST("w", "west"), LEFT("l", "left"), RIGHT("r", "right"), 12 | FORWARD("f", "front", "forward", "forwards", "continue"), 13 | BACKWARD("b", "back", "backward", "backwards", "reverse"), 14 | UP("u", "up", "upwards", "above"), 15 | DOWN("d", "down", "downwards", "below"), 16 | NONE("", "n", "none"); 17 | 18 | private final String[] aliases; 19 | private Direction(String... aliases) { 20 | this.aliases = aliases; 21 | } 22 | 23 | public BlockFace getDirection(BlockFace signfacing) { 24 | return getDirection(signfacing, signfacing.getOppositeFace()); 25 | } 26 | 27 | public BlockFace getDirection(BlockFace signfacing, BlockFace cartdirection) { 28 | switch (this) { 29 | case NORTH : return BlockFace.NORTH; 30 | case EAST : return BlockFace.EAST; 31 | case SOUTH : return BlockFace.SOUTH; 32 | case WEST : return BlockFace.WEST; 33 | case DOWN : return BlockFace.DOWN; 34 | case UP : return BlockFace.UP; 35 | case LEFT : return FaceUtil.rotate(signfacing, 2); 36 | case RIGHT : return FaceUtil.rotate(signfacing, -2); 37 | case FORWARD : return cartdirection; 38 | case BACKWARD : return cartdirection.getOppositeFace(); 39 | default : return cartdirection; 40 | } 41 | } 42 | 43 | public boolean match(char character) { 44 | for (String alias : this.aliases) { 45 | if (alias.length() == 1 && alias.charAt(0) == character) { 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | public boolean match(String text) { 53 | for (String alias : this.aliases) { 54 | if (alias.equalsIgnoreCase(text)) return true; 55 | } 56 | return false; 57 | } 58 | 59 | public static Direction parse(char character) { 60 | for (Direction dir : values()) { 61 | if (dir.match(character)) return dir; 62 | } 63 | return NONE; 64 | } 65 | 66 | public static Direction parse(String text) { 67 | for (Direction dir : values()) { 68 | if (dir.match(text)) return dir; 69 | } 70 | return NONE; 71 | } 72 | 73 | public static Direction fromFace(BlockFace face) { 74 | switch (face) { 75 | case NORTH : return NORTH; 76 | case EAST : return EAST; 77 | case SOUTH : return SOUTH; 78 | case WEST : return WEST; 79 | case UP : return UP; 80 | case DOWN : return DOWN; 81 | case SELF : return FORWARD; 82 | default : return NONE; 83 | } 84 | } 85 | 86 | public static Direction[] parseAll(String text) { 87 | if (text.equalsIgnoreCase("all") || text.equals("*")) { 88 | Direction[] dirs = new Direction[FaceUtil.BLOCK_SIDES.length]; 89 | for (int i = 0; i < dirs.length; i++) { 90 | dirs[i] = fromFace(FaceUtil.BLOCK_SIDES[i]); 91 | } 92 | return dirs; 93 | } else { 94 | LinkedHashSet faces = new LinkedHashSet(); 95 | Direction dir = Direction.parse(text); 96 | if (dir == Direction.NONE) { 97 | for (char c : text.toCharArray()) { 98 | dir = Direction.parse(c); 99 | if (dir == Direction.NONE) { 100 | return new Direction[0]; 101 | } else { 102 | faces.add(dir); 103 | } 104 | } 105 | } else { 106 | faces.add(dir); 107 | } 108 | return faces.toArray(new Direction[0]); 109 | } 110 | } 111 | 112 | public static BlockFace[] parseAll(String text, BlockFace absoluteDirection) { 113 | Direction[] dirs = parseAll(text); 114 | BlockFace[] faces = new BlockFace[dirs.length]; 115 | for (int i = 0; i < faces.length; i++) { 116 | faces[i] = dirs[i].getDirection(absoluteDirection); 117 | } 118 | return faces; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/bergerkiller/bukkit/tc/controller/components/BlockTracker.java: -------------------------------------------------------------------------------- 1 | package com.bergerkiller.bukkit.tc.controller.components; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.LinkedHashSet; 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | import org.bukkit.block.Block; 12 | 13 | import com.bergerkiller.bukkit.common.ToggledState; 14 | import com.bergerkiller.bukkit.tc.detector.DetectorRegion; 15 | 16 | /** 17 | * Keeps track of the active rails, signs and detector regions 18 | */ 19 | public abstract class BlockTracker { 20 | protected static final Set blockBuffer = new HashSet(); 21 | protected final Set activeSigns = new LinkedHashSet(); 22 | protected final List detectorRegions = new ArrayList(0); 23 | protected final ToggledState needsUpdate = new ToggledState(); 24 | 25 | public Collection getActiveSigns() { 26 | return Collections.unmodifiableSet(activeSigns); 27 | } 28 | 29 | public Collection getActiveDetectorRegions() { 30 | return this.detectorRegions; 31 | } 32 | 33 | public boolean containsSign(Block signblock) { 34 | return signblock != null && activeSigns.contains(signblock); 35 | } 36 | 37 | public boolean hasSigns() { 38 | return !this.activeSigns.isEmpty(); 39 | } 40 | 41 | /** 42 | * Clears all active signs and other Block info, resulting in leave events being fired 43 | */ 44 | public void clear() { 45 | if (!activeSigns.isEmpty()) { 46 | for (Block signBlock : activeSigns) { 47 | onSignChange(signBlock, false); 48 | } 49 | activeSigns.clear(); 50 | } 51 | } 52 | 53 | /** 54 | * Tells detector regions (and signs?) that the tracker owner has unloaded 55 | */ 56 | public void unload() { 57 | } 58 | 59 | /** 60 | * Tells all the Minecarts part of this Minecart Member or Group that something changed 61 | */ 62 | public void update() { 63 | needsUpdate.set(); 64 | } 65 | 66 | /** 67 | * Removes an active sign 68 | * 69 | * @param signBlock to remove 70 | * @return True if the Block was removed, False if not 71 | */ 72 | public boolean removeSign(Block signBlock) { 73 | if (activeSigns.remove(signBlock)) { 74 | onSignChange(signBlock, false); 75 | return true; 76 | } else { 77 | return false; 78 | } 79 | } 80 | 81 | /** 82 | * Checks whether the Minecart Member or Group is traveling on top of a given rails block 83 | * 84 | * @param railsBlock to check 85 | * @return True if part of the rails, False if not 86 | */ 87 | public abstract boolean isOnRails(Block railsBlock); 88 | 89 | protected abstract void onSignChange(Block signblock, boolean active); 90 | 91 | protected void updateActiveSigns(Collection newActiveSigns) { 92 | if (newActiveSigns.isEmpty()) { 93 | // Only remove old signs 94 | if (!activeSigns.isEmpty()) { 95 | for (Block oldActiveSign : activeSigns) { 96 | onSignChange(oldActiveSign, false); 97 | } 98 | activeSigns.clear(); 99 | } 100 | } else { 101 | final boolean hadSigns = !activeSigns.isEmpty(); 102 | 103 | // Add all the new signs 104 | for (Block newActiveSign : newActiveSigns) { 105 | if (activeSigns.add(newActiveSign)) { 106 | onSignChange(newActiveSign, true); 107 | } 108 | } 109 | if (hadSigns) { 110 | // Calculate all the signs that are now missing 111 | blockBuffer.clear(); 112 | blockBuffer.addAll(activeSigns); 113 | blockBuffer.removeAll(newActiveSigns); 114 | 115 | // Remove all the signs that are now inactive 116 | activeSigns.removeAll(blockBuffer); 117 | for (Block oldActiveSign : blockBuffer) { 118 | onSignChange(oldActiveSign, false); 119 | } 120 | } 121 | } 122 | } 123 | } 124 | --------------------------------------------------------------------------------