Commits

Ricky Brent committed 6fb12c6

Reverting 1.5.2 back to 1.5.1 -- backwards, never really do this... :(

  • Participants
  • Parent commits 05a76dd
  • Branches 1.5.1

Comments (0)

Files changed (48)

File README_HariboteAirCraft.txt

 
 ## 前提
 
-- Minecraft 1.5.2
-- ModLoader 1.5.2
-- YMTLib_152v1
+- Minecraft 1.5.1
+- ModLoader 1.5.1
+- YMTLib_151v3
 
 
 ## 導入
 - 飛行船は地面などに当たると一旦止まります。
 - 飛行船は一定時間入力がないと、その場で止まります。その時間はConfig[moveKeepTime]から設定できます。(デッドマン装置)
 - 移動中のブロックは見た目だけです。ブロックとしての機能はありません。
-- 一部の非対応ブロックは、移動中の見た目が羊毛ブロックになります。羅針盤をOFFにすると元のブロックに戻ります。
-- 強制停止するときには、はりぼて終了キーを押してください。
 
 
 ## 操作説明(初期値)
 
-    はりぼて前進    = テンキー1    (MaxSpeed = 4)
-    はりぼて後退    = テンキー3    (MaxSpeed = 1)
-    はりぼて上昇    = テンキー8    (MaxSpeed = 4)
-    はりぼて下降    = テンキー2    (MaxSpeed = 4)
-    はりぼて右旋回  = テンキー9    (MaxSpeed = 4)
-    はりぼて左旋回  = テンキー7    (MaxSpeed = 4)
-    はりぼて右移動  = テンキー6    (MaxSpeed = 3)
-    はりぼて左移動  = テンキー4    (MaxSpeed = 3)
-    はりぼて停止    = テンキー5    (停止中に停止するとブロックグリッドに整列)
-    はりぼて終了    = テンキー/    (その場で強制的に再ブロック化)
-
+    はりぼて前進    = テンキー1    (MaxSpeed = 5)
+    はりぼて後退    = テンキー3    (MaxSpeed = 1)
+    はりぼて上昇    = テンキー8    (MaxSpeed = 2)
+    はりぼて下降    = テンキー2    (MaxSpeed = 2)
+    はりぼて右旋回  = テンキー9    (MaxSpeed = 2)
+    はりぼて左旋回  = テンキー7    (MaxSpeed = 2)
+    はりぼて右移動  = テンキー6    (MaxSpeed = 2)
+    はりぼて左移動  = テンキー4    (MaxSpeed = 2)
+    はりぼて停止    = テンキー5    (停止中に停止するとブロックグリッドに整列)
+    
 キーは押し続けたり連打しなくても、1回押すだけでその方向に動き出します。
 キーを重ねて入力するとその方向へスピードアップします。逆方向のキーでスピードダウンします。
 
 
 ## History
 
-- 152v2: 移動スピードなど調整しました。緊急停止ボタンを付けました。ピストン、ビーコン、醸造台などが動かせるようになりました。
-- 152v1: Minecraft1.5.2 に対応。一部の非対応ブロックを羊毛として描写する仕様にしました。
 - 151v2: 描画系の処理を見直し、軽量化を図りました。チェスト、かまどなどが動かせるようになりました。Java6 で動かない部分を修正しました。
 - 151v1: Minecraft1.5.1 に対応。1.5.1から追加されたブロックを一部動かせるようになりました。
 - 147v2: 旋回に伴ってプレイヤーも方向を変えるようになりました。ドア、ベッド、植木鉢などが動かせるようになりました。
          26     Bed                         ベッド
          27     Powered Rail                パワードレール
          28     Detector Rail               ディテクターレール
-         29     Sticky Piston               粘着ピストン
          30     Web                         クモの巣
          31     Tall Grass                  背の高い草
          32     Dead Shrub                  枯れ木
-         33     Piston                      ピストン
-         34     Piston Head                 ピストンアーム
          35     Wool                        羊毛
          37     Dandelion                   花
          38     Rose                        バラ
          113    Nether Brick Fence          ネザーレンガフェンス
          114    Nether Brick Stairs         ネザーレンガの階段
          115    Nether Wart                 ネザーいぼ
-         116    Enchantment Table           エンチャント台
-         117    Brewing Stand               醸造台
          118    Cauldron                    大釜
          121    End Stone                   エンドストーン
          122    Dragon Egg                  ドラゴンエッグ
          134    Spruce Wood Stairs          木の階段(松)
          135    Birch Wood Stairs           木の階段(白樺)
          136    Jungle Wood Stairs          木の階段(ジャングル)
-         137    Command Block               コマンドブロック
-         138    Beacon                      ビーコン
          139    Cobblestone Wall            丸石フェンス
          140    Flower Pot                  植木鉢
          141    Carrots                     ニンジン
          142    Potatoes                    じゃがいも
          143    Wooden Button               木ボタン
          145    Anvil                       金床
-         146    TrappedChest                トラップチェスト
          147    Weighted Pressure Plate     金の感圧板
          148    Weighted Pressure Plate     鉄の感圧板
-         149    Redstone Comparator         レッドストーンコンパレータ
-         150    Redstone Comparator         レッドストーンコンパレータ
-         151    Daylight Sensor             太陽光センサー
          152    Redstone Block              レッドストーンブロック
          153    Nether Quartz Ore           ネザー水晶鉱石
-         154    Hopper                      ホッパー
          155    Nether Quartz Block         ネザー水晶ブロック
          156    Quartz Stairs               水晶の階段
          157    Activator Rail              作動レール

File mod/ymt/air/AirCraftCore.java

 import mod.ymt.air.op.LadderOperator;
 import mod.ymt.air.op.LeverOperator;
 import mod.ymt.air.op.NormalOperator;
-import mod.ymt.air.op.NullOperator;
-import mod.ymt.air.op.PistonOperator;
 import mod.ymt.air.op.RailOperator;
 import mod.ymt.air.op.RailPoweredOperator;
 import mod.ymt.air.op.StairsOperator;
 import net.minecraft.src.BaseMod;
 import net.minecraft.src.Block;
 import net.minecraft.src.Entity;
-import net.minecraft.src.ITileEntityProvider;
 import net.minecraft.src.Item;
 import net.minecraft.src.ItemStack;
 import net.minecraft.src.ModLoader;
 	private static final boolean DEBUG_RENDER_INVISIBLE = false;
 	private static final boolean DEBUG_RENDER_MAT = false;
 	private static final AirCraftCore instance = new AirCraftCore();
-	
+
 	private int blockIdPyxis = 209;
 	private int blocklimit = 2000;
 	private int craftBodySize = -1;
 	private int moveKeepTime = 20 * 60;
-	
+
 	private int entityIdPyxis = 0;
 	private int entityIdInvisible = 0;
 	private int entityIdMobMat = 0;
-	
+
 	private BaseMod baseMod = null;
 	private Block blockPyxis = null;
-	
+
 	public final AirCraftNetHandler net = new AirCraftNetHandler(this);
 	private final Operator[] blockops = new Operator[Block.blocksList.length];
 	private final Collection<EntityImitator> imitatorServer = new WeakEntityCollection<EntityImitator>();
 	private final Collection<EntityImitator> imitatorClient = new WeakEntityCollection<EntityImitator>();
-	
+
 	public final Set<Integer> targetBlockId = new TreeSet<Integer>();
 	public final Set<Integer> appendixBlockId = new TreeSet<Integer>();
 	public final Set<Integer> ignoredBlockId = new TreeSet<Integer>();
-	
+
 	private AirCraftCore() {
 		;
 	}
-	
+
 	public void addRenderer(Map map) {
 		// Imitator
 		if (DEBUG_RENDER_IMITATOR)
 			map.put(EntityImitator.class, new RenderDebugEntity(Block.blockDiamond));
 		else
 			map.put(EntityImitator.class, new RenderPyxis());
-		
+
 		// Invisible
 		if (DEBUG_RENDER_INVISIBLE)
 			map.put(EntityCraftBody.class, new RenderDebugEntity(Block.glass));
 		else
 			map.put(EntityCraftBody.class, new RenderNothing());
-		
+
 		// Mat
 		if (DEBUG_RENDER_MAT)
 			map.put(EntityMobMat.class, new RenderDebugEntity(Block.cloth));
 		else
 			map.put(EntityMobMat.class, new RenderNothing());
 	}
-	
+
 	public int getBlockIdPyxis() {
 		return blockIdPyxis;
 	}
-	
+
 	public Operator getBlockOperator(int blockId) {
 		if (0 < blockId && blockId < blockops.length) {
 			Operator result = blockops[blockId];
 				return result;
 			}
 		}
-		return NullOperator.INSTANCE;
+		return NormalOperator.INSTANCE;
 	}
-	
+
 	public Block getBlockPyxis() {
 		return blockPyxis;
 	}
-	
+
 	public int getCraftBodySize() {
 		return craftBodySize;
 	}
-	
+
 	public Set<Integer> getDefaultMoveableSet() {
 		Set<Integer> result = new TreeSet<Integer>();
 		for (int i = 0; i < blockops.length; i++) { // target が未指定の時には defaultMoveableSet
 		}
 		return result;
 	}
-	
+
 	public Set<Integer> getMoveableBlockIds() {
 		Set<Integer> result = new HashSet<Integer>();
-		
+
 		// targetBlockId
 		if (targetBlockId.isEmpty())
 			result.addAll(getDefaultMoveableSet());
 		else
 			result.addAll(targetBlockId);
-		
+
 		// appendixBlockId
 		result.addAll(appendixBlockId);
-		
+
 		// ignoredBlockId
 		result.removeAll(ignoredBlockId);
-		
+
 		// その他
 		result.remove(0); // 空気ブロックは移動禁止
 		result.remove(Block.bedrock.blockID); // 岩盤は移動禁止
-		
+
 		// 完成
 		return result;
 	}
-	
+
 	public int getMoveKeepTime() {
 		return moveKeepTime;
 	}
-	
+
 	public Materializer newMaterializer(World world, ImitationSpace space) {
 		Set<Integer> moveable = Utils.isServerSide(world) ? getMoveableBlockIds() : new TreeSet<Integer>();
 		return new Materializer(world, space, blocklimit, moveable);
 	}
-	
+
 	public AirCraftMoveHandler newMoveHandler(World worldObj, EntityCraftCore craftCore, String playerName) {
 		return new AirCraftMoveHandler(craftCore, playerName, getMoveKeepTime());
 	}
-	
+
 	public void processAppendSemiSurface(int entId, byte[] data) {
 		synchronized (imitatorClient) {
 			for (EntityImitator cli: imitatorClient) {
 			}
 		}
 	}
-	
+
 	public void processAppendSurface(int entId, byte[] data) {
 		synchronized (imitatorClient) {
 			for (EntityImitator cli: imitatorClient) {
 			}
 		}
 	}
-	
+
 	public void processAppendTileEntityData(int entId, byte[] data) {
 		synchronized (imitatorClient) {
 			for (EntityImitator cli: imitatorClient) {
 			}
 		}
 	}
-	
+
 	public void processMoveClient(byte type, String name) {
 		processMove(imitatorClient, type, name);
 	}
-	
+
 	public void processMoveServer(byte type, String name) {
 		processMove(imitatorServer, type, name);
 	}
-	
+
 	public void processRequestSurfaces(int entId) {
 		synchronized (imitatorServer) {
 			for (EntityImitator svr: imitatorServer) {
 			}
 		}
 	}
-	
+
 	public void registerImitator(EntityImitator imitator) {
 		if (Utils.isServerSide(imitator.worldObj)) {
 			synchronized (imitatorServer) {
 			}
 		}
 	}
-	
+
 	public void setBaseMod(BaseMod baseMod) {
 		this.baseMod = baseMod;
 	}
-	
+
 	public void setBlockIdPyxis(int blockIdPyxis) {
 		this.blockIdPyxis = blockIdPyxis;
 	}
-	
+
 	public void setBlocklimit(int blocklimit) {
 		this.blocklimit = blocklimit;
 	}
-	
+
 	public void setBlockOperator(int blockId, Operator operator) {
 		if (0 < blockId && blockId < blockops.length) {
 			if (blockops[blockId] != null) {
 			blockops[blockId] = operator;
 		}
 	}
-	
+
 	public void setCraftBodySize(int craftBodySize) {
 		this.craftBodySize = craftBodySize;
 	}
-	
+
 	public void setMoveKeepTime(int moveKeepTime) {
 		this.moveKeepTime = moveKeepTime;
 	}
-	
+
 	public Entity spawnEntity(int entId, World world, double x, double y, double z) {
 		Entity result = null;
 		{
 		}
 		return result;
 	}
-	
-	public BlockData toSafeClientBlock(BlockData data) {
-		// TODO renderStrategy オプションを追加
-		// 2 = 変換しない
-		// 1 = Operator の無いブロックを変換
-		// 0 = Operator の無い BlockContainer を変換
-		// -1 = 常に羊毛に変換
-		if (getBlockOperator(data.block.blockID) instanceof NullOperator == false) {
-			// Operator が存在するなら安全
-			return data;
-		}
-		if (data.block instanceof ITileEntityProvider == false) {
-			// BlockContainer でなければたぶん安全
-			return data;
-		}
-		// 安全でないものは Block.cloth に変換
-		debugPrint("toSafeClientBlock [%s:%s] %s", data.block.blockID, data.metadata, data.block);
-		return new BlockData(Block.cloth, data.metadata, data.relPos, data.absPos);
-	}
-	
+
 	protected Operator[] getDefaultOperators() {
 		return new Operator[]{
-			new NormalOperator(),
+			NormalOperator.INSTANCE,
 			new DelicateOperator(),
 			new DirectionalOperator(),
 			new DelicateDirectionalOperator(),
 			new ChestOperator(),
 			new EnderChestOperator(),
 			new AnvilOperator(),
-			new PistonOperator(),
-		//			new EndPortalOperator(),
 		};
 	}
-	
+
 	@Override
 	protected void init() {
 		if (0 < blockIdPyxis) {
 			ModLoader.addRecipe(new ItemStack(blockPyxis), new Object[]{
 				" C ", "DGD", "OOO", 'C', Item.compass, 'D', Item.diamond, 'G', Block.blockGold, 'O', Block.obsidian
 			});
-			
+
 			// エンティティ登録
 			ModLoader.registerEntityID(EntityPyxis.class, "HAC_Pyxis", entityIdPyxis = Utils.getUnusedEntityID());
 			ModLoader.registerEntityID(EntityCraftBody.class, "HAC_CraftBody", entityIdInvisible = Utils.getUnusedEntityID());
 			ModLoader.addEntityTracker(baseMod, EntityPyxis.class, entityIdPyxis, 256, 4, true); // 描写距離とりあえず広めにとる
 			ModLoader.addEntityTracker(baseMod, EntityCraftBody.class, entityIdInvisible, 32, 4, true);
 			ModLoader.addEntityTracker(baseMod, EntityMobMat.class, entityIdMobMat, 32, 4, true);
-			
+
 			// チャネル登録
 			net.registerPacketChannel(baseMod);
-			
+
 			// Operator 登録
 			for (Operator op: getDefaultOperators()) {
 				op.register(this);
 			}
 		}
 	}
-	
+
 	protected void processMove(Collection<EntityImitator> imitators, byte type, String name) {
 		synchronized (imitators) {
 			for (EntityCraftCore imitator: imitators) {
 			}
 		}
 	}
-	
+
 	public static AirCraftCore getInstance() {
 		return instance;
 	}

File mod/ymt/air/AirCraftMoveHandler.java

 	public static final byte PROC_DOWN = 6;
 	public static final byte PROC_RIGHT = 7;
 	public static final byte PROC_LEFT = 8;
-	public static final byte PROC_TERMINATE = 9;
-	
+
 	public final EntityCraftCore owner;
 	public final int keepTime;
-	
+
 	public String playerName = null;
 	private boolean craftMoving = false;
 	private int speedForward = 0;
 	private int rightSlide = 0;
 	private int rightTurn = 0;
 	private int movingCount = 0;
-	
+
 	public AirCraftMoveHandler(EntityCraftCore owner, String playerName, int keepTime) {
 		this.owner = owner;
 		this.playerName = playerName;
 		this.keepTime = 0 < keepTime ? keepTime : 20 * 60;
 	}
-	
+
 	public String getPlayerName() {
 		return playerName;
 	}
-	
+
 	public boolean isCraftMoving() {
 		return craftMoving;
 	}
-	
+
 	public void onTick() {
 		craftMoving = false;
 		owner.motionX = owner.motionY = owner.motionZ = 0;
 		float motionYaw = 0;
-		
+
 		if (owner.isDead) {
 			return;
 		}
 			craftMoving = true;
 		}
 		if (upSlide != 0) {
-			owner.motionY = 0.08 * upSlide;
+			owner.motionY = 0.05 * upSlide;
 			craftMoving = true;
 		}
 		if (rightTurn != 0) {
-			motionYaw = 0.2f * rightTurn;
+			motionYaw = 0.5f * rightTurn;
 			craftMoving = true;
 		}
-		
+
 		if (craftMoving) {
 			// 移動
 			owner.moveCraft(owner.motionX, owner.motionY, owner.motionZ, motionYaw, 0);
 			}
 		}
 	}
-	
+
 	public void process(String sender, byte type) {
 		if (owner.isDead) {
 			return;
 		keepOnProcess();
 		if (sender == null || sender.equals(this.playerName)) {
 			switch (type) {
-				case PROC_TERMINATE:
-					processStop();
-					owner.terminate();
-					break;
 				case PROC_STOP:
 					if (craftMoving) {
 						processStop();
 			}
 		}
 	}
-	
+
 	public void processStop() {
 		owner.stopImmediately();
 		setForward(0);
 		setUpSlide(0);
 		keepOnProcess();
 	}
-	
+
 	public void setPlayerName(String name) {
 		this.playerName = name;
 	}
-	
+
 	public void stopAllServerAndClient() {
 		AirCraftCore core = AirCraftCore.getInstance();
 		if (Utils.isServerSide(owner.worldObj)) {
 			core.net.sendMoveStopToServerAndClients(playerName);
 		}
 	}
-	
+
 	private void keepOnProcess() {
 		movingCount = 0;
 	}
-	
+
 	protected int clip(int value, int min, int max) {
 		if (value < min)
 			return min;
 			return max;
 		return value;
 	}
-	
+
 	protected void setForward(int value) {
-		this.forward = clip(value, -1, 4);
+		this.forward = clip(value, -1, 5);
 		if (forward <= 0) {
 			this.speedForward = forward;
 		}
 			this.speedForward = MathHelper.floor_double(Math.pow(2, forward - 1));
 		}
 	}
-	
+
 	protected void setRightSlide(int value) {
-		this.rightSlide = clip(value, -3, 3);
+		this.rightSlide = clip(value, -2, 2);
 	}
-	
+
 	protected void setRightTurn(int value) {
-		this.rightTurn = clip(value, -4, 4);
+		this.rightTurn = clip(value, -2, 2);
 	}
-	
+
 	protected void setUpSlide(int value) {
-		this.upSlide = clip(value, -4, 4);
+		this.upSlide = clip(value, -3, 3);
 	}
 }

File mod/ymt/air/AirCraftNetHandler.java

 	 * タイルエンティティデータ返却チャンネル(サーバ→クライアント)
 	 */
 	public static final String HAAC_TILE = "HAAC|TILE";
-	
+
 	protected final AirCraftCore core;
-	
+
 	public AirCraftNetHandler(AirCraftCore core) {
 		this.core = core;
 	}
-	
+
 	public void processClientCustomPayload(Packet250CustomPayload packet) {
 		if (HAAC_CTRL.equals(packet.channel)) {
 			core.processMoveClient(packet.data[0], readPlayerNameFromControl(packet));
 		}
 		core.debugPrint("client receive unknown packet [ %s ]", packet.channel);
 	}
-	
+
 	public void processServerCustomPayload(Packet250CustomPayload packet) {
 		if (HAAC_CTRL.equals(packet.channel)) {
 			sendToClients(packet); // サーバに届いたパケットを全クライアントへ転送
 		}
 		core.debugPrint("server receive unknown packet [ %s ]", packet.channel);
 	}
-	
+
 	public void registerPacketChannel(BaseMod baseMod) {
 		ModLoader.registerPacketChannel(baseMod, HAAC_CTRL);
 		ModLoader.registerPacketChannel(baseMod, HAAC_REQSUR);
 		ModLoader.registerPacketChannel(baseMod, HAAC_SEMISUR);
 		ModLoader.registerPacketChannel(baseMod, HAAC_TILE);
 	}
-	
+
 	public void sendKeyToServer(byte key) {
 		sendToServer(newControl(key, clientUserName()));
 	}
-	
+
 	public void sendMoveStopToServerAndClients(String playerName) {
 		core.debugPrint("sendMoveStopToClients %s", playerName);
 		processServerCustomPayload(newControl(AirCraftMoveHandler.PROC_STOP, playerName));
 	}
-	
+
 	public void sendRequestSurfacesToServer(int entityId) {
 		core.debugPrint("sendRequestSurfacesToServer: sender = %s", entityId);
 		sendToServer(newRequestSurface(entityId));
 	}
-	
+
 	public void sendSemiSurfaceToClient(int entityId, byte[] data) {
 		core.debugPrint("sendSemiSurfaceToClient: sender = %s", entityId);
 		sendToClients(newAddSurface(HAAC_SEMISUR, entityId, data));
 	}
-	
+
 	public void sendSurfaceToClient(int entityId, byte[] data) {
 		core.debugPrint("sendSurfaceToClient: sender = %s", entityId);
 		sendToClients(newAddSurface(HAAC_SUR, entityId, data));
 	}
-	
+
 	public void sendTileDataToClient(int entityId, byte[] data) {
 		core.debugPrint("sendTileDataToClient: sender = %s", entityId);
 		sendToClients(newAddSurface(HAAC_TILE, entityId, data));
 	}
-	
+
 	protected int getInt(byte[] data, int index) {
 		return ByteBuffer.wrap(data).getInt(index);
 	}
-	
+
 	protected Packet250CustomPayload newAddSurface(String channel, int entityId, byte[] surface) {
 		byte[] data = new byte[surface.length + 4];
 		putInt(data, 0, entityId);
 		System.arraycopy(surface, 0, data, 4, surface.length);
 		return new Packet250CustomPayload(channel, data);
 	}
-	
+
 	protected Packet250CustomPayload newControl(byte type, String name) {
 		byte[] nameData = name.getBytes();
 		byte[] data = new byte[nameData.length + 1];
 		System.arraycopy(nameData, 0, data, 1, nameData.length);
 		return new Packet250CustomPayload(HAAC_CTRL, data);
 	}
-	
+
 	protected Packet250CustomPayload newRequestSurface(int entityId) {
 		return new Packet250CustomPayload(HAAC_REQSUR, ByteBuffer.allocate(4).putInt(entityId).array());
 	}
-	
+
 	protected byte[] putInt(byte[] data, int index, int value) {
 		ByteBuffer.wrap(data).putInt(index, value);
 		return data;
 	}
-	
+
 	protected byte[] readDataFromSurface(Packet250CustomPayload packet) {
 		byte[] data = new byte[packet.data.length - 4];
 		System.arraycopy(packet.data, 4, data, 0, data.length);
 		return data;
 	}
-	
+
 	protected int readEntityIdFromSurface(Packet250CustomPayload packet) {
 		return getInt(packet.data, 0);
 	}
-	
+
 	protected String readPlayerNameFromControl(Packet250CustomPayload packet) {
 		byte[] data = packet.data;
 		return data == null || data.length <= 1 ? "" : new String(data, 1, data.length - 1);
 	}
-	
+
 	private static String clientUserName() {
 		Minecraft mc = ModLoader.getMinecraftInstance();
 		if (mc != null && mc.session != null && mc.session.username != null)
 			return mc.session.username;
 		return "";
 	}
-	
+
 	private static void sendToClients(Packet packet) {
 		MinecraftServer.getServer().getConfigurationManager().sendPacketToAllPlayers(packet);
 	}
-	
+
 	private static void sendToServer(Packet packet) {
 		ModLoader.clientSendPacket(packet);
 	}

File mod/ymt/air/BlockData.java

 	public final int metadata;
 	public final Coord3D relPos;
 	public final Coord3D absPos;
-	
+
 	public BlockData(Block block, int metadata, Coord3D relPos, Coord3D absPos) {
 		if (block == null || relPos == null || absPos == null)
 			throw new NullPointerException("argument must not null");
 		this.relPos = relPos;
 		this.absPos = absPos;
 	}
-	
+
 	@Override
 	public boolean equals(Object obj) {
 		if (this == obj)
 			return false;
 		return true;
 	}
-	
+
 	@Override
 	public int hashCode() {
 		final int prime = 31;
 		result = prime * result + absPos.hashCode();
 		return result;
 	}
-	
+
 	@Override
 	public String toString() {
 		return "BlockData [block=" + block + ", metadata=" + metadata + ", relPos=" + relPos + ", absPos=" + absPos + "]";
 	}
-	
+
 	public void write(DataOutput output) throws IOException {
 		int blocks = pack(block.blockID, metadata);
 		if ((blocks & 0xFF00) != 0xFF00 && isByte(relPos.x) && isByte(relPos.y) && isByte(relPos.z)) {
 		}
 		// 書き込みサイズが変わると Packet250CustomPayload 用の分割数が変わってくるので注意
 	}
-	
+
 	public static int pack(int blockId, int metadata) {
 		return (blockId << 4) | (metadata & 15);
 	}
-	
+
 	public static BlockData read(DataInput input, Coord3D base) throws IOException {
 		byte first = input.readByte();
 		if (first == -1) {
 			return valueOf(unpackBlockId(block), unpackMetadata(block), relPos, relPos.add(base));
 		}
 	}
-	
+
 	public static int unpackBlockId(int block) {
 		return block >>> 4;
 	}
-	
+
 	public static int unpackMetadata(int block) {
 		return block & 15;
 	}
-	
+
 	public static BlockData valueOf(int blockId, int metadata, Coord3D relPos, Coord3D absPos) {
 		Block block = Utils.getBlock(blockId);
 		if (block != null) {
 		}
 		return null;
 	}
-	
+
 	private static boolean isByte(int value) {
 		return ((byte) value) == value;
 	}

File mod/ymt/air/BlockDataBottomUpComparator.java

 			result = Utils.compare(o1.relPos.y, o2.relPos.y);
 		return result;
 	}
-}
+}

File mod/ymt/air/BlockDataRenderingComparator.java

 			}
 		}
 	}
-	
+
 	@Override
 	public int compare(BlockData o1, BlockData o2) {
 		int result = 0;
 			result = Utils.compare(o1.relPos.z, o2.relPos.z);
 		return result;
 	}
-}
+}

File mod/ymt/air/BlockPyxis.java

  */
 public class BlockPyxis extends Block {
 	private Icon[] icons = new Icon[6];
-	
+
 	public BlockPyxis(int blockId) {
 		super(blockId, Material.rock);
 		setHardness(0.5F);
 		setLightValue(1.0F); // 光源になるよ
 		this.setCreativeTab(CreativeTabs.tabTransport); // 乗り物タブ
 	}
-	
+
 	@Override
-	public Icon getIcon(int side, int metadata) {
+	public Icon getBlockTextureFromSideAndMetadata(int side, int metadata) {
 		switch (side) {
 			case 0: // 底面
 				return icons[0];
 				return icons[1];
 		}
 	}
-	
+
 	@Override
 	public boolean isOpaqueCube() {
 		return false;
 	}
-	
+
 	@Override
 	public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) {
 		AirCraftCore core = AirCraftCore.getInstance();
 		}
 		return true;
 	}
-	
+
 	@Override
 	public void onBlockPlacedBy(World world, int x, int y, int z, EntityLiving player, ItemStack stack) {
 		int metadata = getDirection(player);
 		world.setBlockMetadataWithNotify(x, y, z, metadata, 2);
 	}
-	
+
+	protected Entity newPyxis(World world, EntityPlayer player, int metadata, Coord3D basePos) {
+		Entity ent = new EntityPyxis(player.getEntityName(), world, blockID, metadata, basePos);
+		ent.setPosition(basePos.x + 0.5, basePos.y, basePos.z + 0.5);
+		return ent;
+	}
+
+	private static int getDirection(Entity ent) {
+		return MathHelper.floor_double((ent.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
+	}
+
 	@Override
 	public void registerIcons(IconRegister ir) {
 		icons = new Icon[]{
 			ir.registerIcon("mod.ymt.air.py_top3"),
 		};
 	}
-	
-	protected Entity newPyxis(World world, EntityPlayer player, int metadata, Coord3D basePos) {
-		Entity ent = new EntityPyxis(player.getEntityName(), world, blockID, metadata, basePos);
-		ent.setPosition(basePos.x + 0.5, basePos.y, basePos.z + 0.5);
-		return ent;
-	}
-	
-	private static int getDirection(Entity ent) {
-		return MathHelper.floor_double((ent.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
-	}
 }

File mod/ymt/air/Coord3DTopDownComparator.java

 			result = Utils.compare(o2.z, o1.z);
 		return result;
 	}
-}
+}

File mod/ymt/air/EntityAirCraft.java

 	 */
 	protected final int DWKEY_OWNERNAME = 11;
 	protected boolean captured = false;
-	
+
 	protected double nextPosX, nextPosY, nextPosZ;
 	protected float nextYaw, nextPitch;
 	protected int turnProgress = 0;
-	
+
 	protected EntityAirCraft(World world) {
 		super(world);
 		this.preventEntitySpawning = true;
 		this.isImmuneToFire = true; // 炎は無敵
 		this.noClip = true;
 	}
-	
+
 	@Override
 	public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) {
 		return false; // 無敵
 	}
-	
+
 	@Override
 	public boolean canBeCollidedWith() {
 		return !isDead;
 	}
-	
+
 	@Override
 	public AxisAlignedBB getBoundingBox() {
 		return this.boundingBox;
 	}
-	
+
 	@Override
 	public float getBrightness(float par1) {
 		return worldObj.provider.lightBrightnessTable[15]; // TODO 15をもっと賢く
 	}
-	
+
 	public String getOwnerName() {
 		return dataWatcher.getWatchableObjectString(DWKEY_OWNERNAME);
 	}
-	
+
 	public List<Entity> getRiddingEntities() {
 		List<Entity> result = new ArrayList<Entity>();
 		findRiddingEntities(result);
 		return result;
 	}
-	
+
 	@Override
 	public float getShadowSize() {
 		return 0.0F;
 	}
-	
+
 	public boolean hasOwnerName() {
 		return Utils.hasString(getOwnerName());
 	}
-	
+
 	public boolean isEntityHitBlocks() {
 		AxisAlignedBB aabb = getBoundingBox();
-		return aabb != null && worldObj.getCollidingBlockBounds(aabb).size() != 0;
+		return aabb != null && worldObj.getAllCollidingBoundingBoxes(aabb).size() != 0;
 	}
-	
+
 	@Override
 	public void onEntityUpdate() {
 		if (this.ridingEntity != null && this.ridingEntity.isDead) {
 		this.prevPosZ = this.posZ;
 		this.prevRotationPitch = this.rotationPitch;
 		this.prevRotationYaw = this.rotationYaw;
-		
+
 		if (isDead) {
 			return;
 		}
 			}
 		}
 	}
-	
+
 	@Override
 	public void readEntityFromNBT(NBTTagCompound tag) {
 		String name = tag.getString("OwnerName");
 			setOwnerName(name);
 		}
 	}
-	
+
 	public void setNextPosition(double x, double y, double z, float yaw, float pitch, int turn) {
 		nextPosX = x;
 		nextPosY = y;
 			super.setRotation(nextYaw, nextPitch);
 		}
 	}
-	
+
 	@Override
 	public void setPositionAndRotation(double x, double y, double z, float yaw, float pitch) {
 		super.setPosition(x, y, z);
 		super.setRotation(yaw, pitch);
 	}
-	
+
 	@Override
 	public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int turn) {
 		setNextPosition(x, y, z, yaw, pitch, 5);
 	}
-	
+
 	public void stopImmediately() {
 		// このエンティティの停止
 		this.isAirBorne = true; // 強制更新
 		setNextPosition(posX, posY, posZ, rotationYaw, rotationPitch, 0); // 現在位置を即座に更新
 	}
-	
+
 	@Override
 	public void writeEntityToNBT(NBTTagCompound tag) {
 		String name = getOwnerName();
 			tag.setString("OwnerName", name);
 		}
 	}
-	
+
 	protected void capturePassenger(Entity ent) {
 		EntityMobMat mat = new EntityMobMat(worldObj, getOwnerName());
-		// double y = Math.max(ent.posY, this.posY + this.height); // 位置補正
-		double y = ent.posY;
-		mat.setPosition(ent.posX, y, ent.posZ);
+		mat.setPosition(ent.posX, ent.posY, ent.posZ);
 		worldObj.spawnEntityInWorld(mat);
 		ent.mountEntity(mat); // ent を mat に載せる
 	}
-	
+
 	protected void capturePassengers() {
 		for (Entity ent: getRiddingEntities()) {
 			if (isUnCapturedPassenger(ent)) {
 			}
 		}
 	}
-	
+
 	@Override
 	protected void entityInit() {
 		dataWatcher.addObject(DWKEY_OWNERNAME, "");
 	}
-	
+
 	protected void findRiddingEntities(List<Entity> result) {
 		// 参考: World#selectEntitiesWithinAABB
 		AxisAlignedBB aabb = getBoundingBox();
 					chunk.getEntitiesOfTypeWithinAAAB(Entity.class, aabb, result, new IEntitySelector() {
 						@Override
 						public boolean isEntityApplicable(Entity ent) {
-							return ent instanceof EntityAirCraft == false && !ent.isDead && ent.ridingEntity == null;
+							return (ent instanceof EntityAirCraft) == false && !ent.isDead && ent.ridingEntity == null;
 						}
 					});
 				}
 			}
 		}
 	}
-	
+
 	protected boolean isUnCapturedPassenger(Entity ent) {
 		if (ent.ridingEntity != null)
 			return false;
 		return ent instanceof EntityLiving || ent instanceof EntityItem || ent instanceof EntityMinecart || ent instanceof EntityBoat;
 	}
-	
+
 	protected void setOwnerName(String name) {
 		if (name == null) {
 			name = "";

File mod/ymt/air/EntityCraftBody.java

 	public EntityCraftBody(World world) {
 		this(world, null);
 	}
-	
+
 	public EntityCraftBody(World world, String ownerName) {
 		super(world, ownerName);
 	}
-	
+
 	@Override
 	public boolean interact(EntityPlayer player) {
 		if (core.tryInteractServer(worldObj)) {
 			capturePassengers(); // 効果範囲にいる子を乗せる
-			return true;
 		}
-		return false;
+		return true;
 	}
 	
 	@Override

File mod/ymt/air/EntityCraftCore.java

  */
 public abstract class EntityCraftCore extends EntityAirCraft {
 	protected final List<EntityAirCraft> subEntity = new ArrayList<EntityAirCraft>();
-	
+
 	public EntityCraftCore(World world) {
 		super(world);
 	}
-	
+
 	public void addSubEntity(EntityAirCraft ent) {
 		subEntity.add(ent);
 	}
-	
+
 	public boolean adjustPositionAndRotation() {
 		this.isAirBorne = true; // 強制更新
 		double x = Math.floor(posX) + 0.5;
 		int d = getDirection(this);
 		return trySetPositionAndRotation(x, y, z, d * 90, 0);
 	}
-	
+
 	public int getDirectionOffset() {
 		return 0;
 	}
-	
+
 	public void moveCraft(double mx, double my, double mz, float yaw, float pitch) {
 		trySetPositionAndRotation(posX + mx, posY + my, posZ + mz, rotationYaw + yaw, rotationPitch + pitch);
 	}
-	
+
 	public abstract void processMove(String name, byte type);
-	
+
 	@Override
 	public void setPositionAndRotation(double x, double y, double z, float yaw, float pitch) {
 		trySetPositionAndRotation(x, y, z, yaw, pitch);
 	}
-	
+
 	@Override
 	public void stopImmediately() {
 		super.stopImmediately();
 			}
 		}
 	}
-	
-	public abstract void terminate();
-	
+
 	private boolean trySetPositionAndRotation(double x, double y, double z, float yaw, float pitch) {
 		// 動かす前の値を保存
 		double prevPosX = posX;
 			return false; // failure
 		}
 	}
-	
+
 	protected void cleanSubEntity() {
 		Iterator<EntityAirCraft> iter = subEntity.iterator();
 		while (iter.hasNext()) {
 			}
 		}
 	}
-	
+
 	protected void onEntityHitBlocks(EntityAirCraft ent) {
 		core.debugPrint("onEntityHitBlocks %s", ent);
 	}
-	
+
 	protected abstract void onEntityPositionUpdate();
-	
+
 	protected EntityAirCraft tryUpdatePosition(double x, double y, double z, float yaw, float pitch) {
 		super.setNextPosition(x, y, z, yaw, pitch, 1); // これ setPositionAndRotation 使っちゃうと、描画のブレが大きくなっちゃうんだね……
 		if (isEntityHitBlocks()) {
 		}
 		return null;
 	}
-	
+
 	public static EntityCraftCore getEntityCore(World world, String name) {
 		if (name != null) {
 			for (Object obj: world.loadedEntityList) {
 		}
 		return null;
 	}
-	
+
 	protected static int getDirection(Entity ent) {
 		return MathHelper.floor_double((ent.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
 	}

File mod/ymt/air/EntityFollower.java

 	protected double offsetY;
 	protected double offsetRotateYaw;
 	protected int ownerMissingTime = 0;
-	
+
 	protected EntityFollower(World world) {
 		super(world);
 	}
-	
+
 	protected EntityFollower(World world, String ownerName) {
 		super(world);
 		if (ownerName != null) {
 			setOwnerName(ownerName);
 		}
 	}
-	
+
 	public EntityAirCraft getOwner() {
 		return owner;
 	}
-	
+
 	@Override
 	public void onEntityUpdate() {
 		super.onEntityUpdate();
 			setDead();
 		}
 	}
-	
+
 	public void updateFollowerPosition() {
 		if (owner != null) {
 			double angle = offsetAngle + (offsetRotateYaw - owner.rotationYaw) / 180 * Math.PI;
 			setNextPosition(x, y, z, (float) (owner.rotationYaw - offsetRotateYaw), 0, 1);
 		}
 	}
-	
+
 	protected void setOwner(EntityCraftCore owner) {
 		this.owner = owner;
 		if (owner != null) {

File mod/ymt/air/EntityImitator.java

  */
 package mod.ymt.air;
 
-import java.util.Collection;
 import java.util.List;
 import mod.ymt.cmn.Coord3D;
 import mod.ymt.cmn.Utils;
 	 * DataWatcher -> z
 	 */
 	protected final int DWKEY_BLOCK_Z = 15;
-	
+
 	protected final ImitationSpace space;
 	protected State status = State.INIT;
 	protected boolean requestSurfaceFromClient = false;
-	
+
 	protected int glCallList = -1;
 	protected boolean glUpdateList = true;
 	protected boolean glDisposed = false;
-	
+
 	protected EntityImitator(World world) {
 		super(world);
 		this.space = new ImitationSpace(world);
 		this.ignoreFrustumCheck = true; // このエンティティはカメラ外でもレンダリングする
 		core.registerImitator(this);
 	}
-	
+
 	public void addClientSemiSurfaces(byte[] data) {
-		space.addClientNonSurfaceBlocks(deserializeClientBlocks(data));
+		space.addClientNonSurfaceBlocks(newSerializer().deserialize(getThisBlockCoord(), data));
 		glUpdateList = true;
 	}
-	
+
 	public void addClientSurfaces(byte[] data) {
-		space.addClientSurfaceBlocks(deserializeClientBlocks(data));
+		space.addClientSurfaceBlocks(newSerializer().deserialize(getThisBlockCoord(), data));
 		glUpdateList = true;
 	}
-	
+
 	public void addClientTileData(byte[] data) {
 		NBTTagCompound tag = newSerializer().deserializeNBT(data);
 		if (tag != null) {
 			space.setTileEntityData(tag);
 		}
 	}
-	
+
 	public synchronized void dispose() {
 		if (!glDisposed) {
 			if (0 < glCallList) {
 			glDisposed = true;
 		}
 	}
-	
+
 	public ImitationSpace getImitationSpace() {
 		return space;
 	}
-	
+
 	public State getStatus() {
 		return status;
 	}
-	
+
 	public List<BlockData> getSurfaces() {
 		return space.getSurfaceBlocks();
 	}
-	
+
 	@Override
 	public void onEntityUpdate() {
 		super.onEntityUpdate(); // TODO ディメンジョン移動できるようにする
 			}
 		}
 	}
-	
+
 	@Override
 	public void readEntityFromNBT(NBTTagCompound tag) {
 		super.readEntityFromNBT(tag);
 		int this_z = tag.getInteger("ThisBlockZ");
 		byte[] blocksData = tag.getByteArray("Blocks");
 		NBTTagList tileData = tag.getTagList("TileEntities");
-		
+
 		// エンティティ情報を反映
 		setStatus(State.fromCode(status));
-		
+
 		// このブロック情報を反映
 		setThisBlock(block, this_x, this_y, this_z);
 		// 保持しているブロック情報を反映
 		space.setServerAllBlocks(newSerializer().deserialize(new Coord3D(this_x, this_y, this_z), blocksData));
-		
+
 		// 保持している TileEntity 情報を反映
 		for (int i = 0; i < tileData.tagCount(); i++) {
 			NBTBase base = tileData.tagAt(i);
 				core.debugPrint("EntityImitator#writeEntityToNBT unknown tag %s", base);
 		}
 	}
-	
+
 	public void requestSurfaceFromClient() {
 		requestSurfaceFromClient = true;
 	}
-	
+
 	@Override
 	public void setDead() {
 		try {
 			dispose();
 		}
 	}
-	
-	@Override
-	public void terminate() {
-		if (getStatus() == State.RUNNING) {
-			// adjustPositionAndRotation をクライアント側でも実施するように改良したほうがいいかなぁ
-			adjustPositionAndRotation();
-			setStatus(State.PUTBLOCK); // adjust 後には強制ブロック配置
-		}
-	}
-	
+
 	@Override
 	public void writeEntityToNBT(NBTTagCompound tag) {
 		super.writeEntityToNBT(tag);
 		int this_z = base.z;
 		byte[] blockData = newSerializer().serialize(space.getAllBlocks());
 		NBTTagList tileData = new NBTTagList();
-		
+
 		// 保持している TileEntity 情報を書き込み
 		for (NBTTagCompound t: space.getAllTileEntities()) {
 			tileData.appendTag(t.copy());
 		}
-		
+
 		// セット
 		tag.setByte("ImitatorStatus", status);
 		tag.setInteger("ThisBlock", block);
 		tag.setByteArray("Blocks", blockData);
 		tag.setTag("TileEntities", tileData);
 	}
-	
-	protected Collection<BlockData> deserializeClientBlocks(byte[] data) {
-		List<BlockData> blocks = newSerializer().deserialize(getThisBlockCoord(), data);
-		toSafeClientBlocks(blocks);
-		return blocks;
-	}
-	
+
 	@Override
 	protected void entityInit() {
 		super.entityInit();
 		dataWatcher.addObject(DWKEY_BLOCK_Y, 0);
 		dataWatcher.addObject(DWKEY_BLOCK_Z, 0);
 	}
-	
+
 	@Override
 	protected void finalize() throws Throwable {
 		try {
 			dispose();
 		}
 	}
-	
+
 	protected int getThisBlock() {
 		return dataWatcher.getWatchableObjectInt(DWKEY_BLOCK);
 	}
-	
+
 	protected Coord3D getThisBlockCoord() {
 		int x = dataWatcher.getWatchableObjectInt(DWKEY_BLOCK_X);
 		int y = dataWatcher.getWatchableObjectInt(DWKEY_BLOCK_Y);
 		int z = dataWatcher.getWatchableObjectInt(DWKEY_BLOCK_Z);
 		return new Coord3D(x, y, z);
 	}
-	
+
 	protected int getThisBlockId() {
 		return BlockData.unpackBlockId(getThisBlock());
 	}
-	
+
 	protected int getThisBlockMetadata() {
 		return BlockData.unpackMetadata(getThisBlock());
 	}
-	
+
 	protected void initCraftBody(int x, int y, int z) {
 		String ownerName = getOwnerName();
 		int size = core.getCraftBodySize();
 			}
 		}
 	}
-	
+
 	protected Serializer newSerializer() {
 		return new Serializer();
 	}
-	
-	protected void toSafeClientBlocks(List<BlockData> blocks) {
-		for (int i = blocks.size() - 1; 0 <= i; i--) {
-			blocks.set(i, core.toSafeClientBlock(blocks.get(i)));
-		}
-	}
-	
+
 	protected void processSendSurfaceToClient() {
 		// 準表面ブロック送信
 		processSendSurfaceToClient(false); // さきにこっちを送信しておく
 		// タイルデータ送信
 		processSendTileDataToclient();
 	}
-	
+
 	protected void processSendSurfaceToClient(boolean isSurface) {
 		// 小データ 5byte、大データ 15byte、Packet250CustomPayload の最大は 32767
 		// 2048 ブロック毎に区切れば、小 4 + 1 + 5 * 2048 = 10245、大 4 + 1 + 15 * 2048 = 30725 で収まる
 				core.net.sendSemiSurfaceToClient(entityId, data);
 		}
 	}
-	
+
 	protected void processSendTileDataToclient() {
 		final Serializer serializer = newSerializer();
 		for (NBTTagCompound tag: space.getAllTileEntities()) {
 			}
 		}
 	}
-	
+
 	protected void putBlock() { // Side: Server
 		if (Utils.isClientSide(worldObj)) {
 			return;
 		Materializer materializer = core.newMaterializer(worldObj, space);
 		if (materializer.putBlocks(x, y, z, d)) {
 			Utils.showMessage(worldObj, "HariboteAirCraft: Off");
-			setStatus(State.END); // END へ
-		}
-		else {
-			Utils.showMessage(worldObj, "HariboteAirCraft: Can't put block on here");
-			setStatus(State.RUNNING); // RUNNING へ戻す
+			setStatus(State.END);
 		}
 	}
-	
+
 	protected void removeBlock() { // Side: Server
 		if (Utils.isClientSide(worldObj)) {
 			return;
 			setStatus(State.RUNNING);
 		}
 	}
-	
+
 	protected void setStatus(State state) {
 		this.status = state;
 	}
-	
+
 	protected void setThisBlock(int blockId, int metadata, Coord3D point) {
 		setThisBlock(BlockData.pack(blockId, metadata), point.x, point.y, point.z);
 	}
-	
+
 	protected void setThisBlock(int block, int x, int y, int z) {
 		dataWatcher.updateObject(DWKEY_BLOCK, block);
 		dataWatcher.updateObject(DWKEY_BLOCK_X, x);
 		dataWatcher.updateObject(DWKEY_BLOCK_Y, y);
 		dataWatcher.updateObject(DWKEY_BLOCK_Z, z);
 	}
-	
+
 	public enum State {
 		INIT((byte) 0), RUNNING((byte) 1), PUTBLOCK((byte) 2), END((byte) 3);
 		private final byte code;
-		
+
 		private State(byte code) {
 			this.code = code;
 		}
-		
+
 		public byte getCode() {
 			return code;
 		}
-		
+
 		public static State fromCode(byte code) {
 			for (State stt: values()) {
 				if (stt.getCode() == code) {

File mod/ymt/air/EntityMobMat.java

 		setSize(0.5f, 0.0625f);
 		this.noClip = false;
 	}
-	
+
 	public EntityMobMat(World world, String ownerName) {
 		super(world, ownerName);
 		setSize(0.5f, 0.0625f);
 		this.noClip = false;
 	}
-	
+
 	@Override
 	public AxisAlignedBB getBoundingBox() {
 		return null;
 	}
-	
+
 	@Override
 	public boolean interact(EntityPlayer player) {
 		if (core.tryInteractServer(worldObj)) {
 		}
 		return false;
 	}
-	
+
 	@Override
 	public void onEntityUpdate() {
 		super.onEntityUpdate();
 			setDead();
 		}
 	}
-	
+
 	@Override
 	public void setDead() {
 		if (riddenByEntity != null) {
 		}
 		super.setDead();
 	}
-	
+
 	@Override
 	protected void capturePassengers() {
 		; // なにもしない

File mod/ymt/air/EntityPyxis.java

 	 * DataWatcher -> PlayerName
 	 */
 	protected final int DWKEY_PLAYERNAME = 17;
-	
+
 	private final AirCraftMoveHandler moveHandler;
-	
+
 	public EntityPyxis(String playerName, World world, int blockId, int metadata, Coord3D basePoint) { // Server
 		super(world);
 		this.moveHandler = core.newMoveHandler(world, this, playerName);
 		setPlayerName(playerName);
 		setThisBlock(blockId, metadata, basePoint);
 	}
-	
+
 	public EntityPyxis(World world) { // Client
 		super(world);
 		this.setSize(1, 0.5f);
 		this.moveHandler = core.newMoveHandler(world, this, null);
 	}
-	
+
 	@Override
 	public int getDirectionOffset() {
 		return getThisBlockMetadata() & 3;
 	}
-	
+
 	public String getPlayerName() {
 		return dataWatcher.getWatchableObjectString(DWKEY_PLAYERNAME);
 	}
-	
+
 	@Override
 	public boolean interact(EntityPlayer par1EntityPlayer) {
 		if (core.tryInteractServer(worldObj)) {
-			terminate();
+			if (getStatus() == State.RUNNING) {
+				// adjustPositionAndRotation をクライアント側でも実施するように改良したほうがいいかなぁ
+				adjustPositionAndRotation();
+				setStatus(State.PUTBLOCK); // adjust 後には強制ブロック配置
+			}
 		}
 		return true;
 	}
-	
+
 	@Override
 	public void processMove(String sender, byte type) {
 		if (isDead) {
 		}
 		moveHandler.process(sender, type);
 	}
-	
+
 	@Override
 	public void readEntityFromNBT(NBTTagCompound tag) {
 		super.readEntityFromNBT(tag);
 		setPlayerName(tag.getString("PlayerName"));
 	}
-	
+
 	public void setPlayerName(String name) {
 		dataWatcher.updateObject(DWKEY_PLAYERNAME, name);
 	}
-	
+
 	@Override
 	public void writeEntityToNBT(NBTTagCompound tag) {
 		super.writeEntityToNBT(tag);
 		tag.setString("PlayerName", getPlayerName());
 	}
-	
+
 	private String newName() {
 		return "EntityPyxis_" + entityId + "_" + System.currentTimeMillis();
 	}
-	
+
 	@Override
 	protected void entityInit() {
 		super.entityInit();
 		dataWatcher.addObject(DWKEY_PLAYERNAME, "");
 	}
-	
+
 	@Override
 	protected void onEntityHitBlocks(EntityAirCraft ent) {
 		super.onEntityHitBlocks(ent);
 			showMessageToMyPlayer("AirCraft hits ground at " + x + ", " + y + ", " + z);
 		}
 	}
-	
+
 	@Override
 	protected void onEntityPositionUpdate() {
 		if (moveHandler.getPlayerName() == null) {
 		}
 		moveHandler.onTick();
 	}
-	
+
 	protected void showMessageToMyPlayer(String msg) {
 		for (Object ent: worldObj.loadedEntityList) {
 			if (ent instanceof EntityPlayer) {

File mod/ymt/air/ImitationSpace.java

  */
 public class ImitationSpace implements IBlockAccess {
 	private final World parent;
-	
+
 	/**
 	 * 元座標から BlockData へのマップ
 	 */
 	 * カスタムレンダリングするブロック
 	 */
 	private final List<BlockData> customRenderBlocks = new ArrayList<BlockData>();
-	
+
 	public ImitationSpace(World parent) {
 		this.parent = parent;
 	}
-	
+
 	public void addClientNonSurfaceBlocks(Collection<BlockData> blocks) {
 		if (blocks.isEmpty()) {
 			AirCraftCore.getInstance().debugPrint("ImitationSpace#addClientNonSurfaceBlocks empty data");
 			}
 		}
 	}
-	
+
 	public void addClientSurfaceBlocks(Collection<BlockData> surfaces) {
 		if (surfaces.isEmpty()) {
 			AirCraftCore.getInstance().debugPrint("ImitationSpace#addClientSurfaceBlocks empty data");
 			appendClientSurface(surfaces); // 表面を差し替え
 		}
 	}
-	
+
 	public void clear() {
 		this.allBlocks.clear();
 		this.surfaceBlocks.clear();
 		this.semiSurfaceBlocks.clear();
 		this.customRenderBlocks.clear();
 	}
-	
+
 	public int countAllBlocks() {
 		return allBlocks.size();
 	}
-	
+
 	public int countSurfaceBlocks() {
 		return surfaceBlocks.size();
 	}
-	
+
 	@Override
 	public boolean doesBlockHaveSolidTopSurface(int x, int y, int z) { // RenderBlocks で使用
 		Block block = Utils.getBlock(getBlockId(x, y, z));
 		}
 		return false;
 	}
-	
+
 	@Override
 	public boolean extendedLevelsInChunkCache() { // 未使用
 		throw new UnsupportedOperationException("method not implemented");
 	}
-	
+
 	public Collection<BlockData> getAllBlocks() {
 		return allBlocks.values();
 	}
-	
+
 	public List<NBTTagCompound> getAllTileEntities() {
 		return new ArrayList<NBTTagCompound>(allTileData.values());
 	}
-	
+
 	@Override
 	public BiomeGenBase getBiomeGenForCoords(int x, int z) { // RenderBlocks で使用
 		return BiomeGenBase.plains;
 	}
-	
+
 	@Override
 	public int getBlockId(int x, int y, int z) { // RenderBlocks で使用
 		BlockData data = getBlockData(x, y, z);
 		}
 		return 0;
 	}
-	
+
 	@Override
 	public Material getBlockMaterial(int x, int y, int z) { // RenderBlocks で使用
 		BlockData data = getBlockData(x, y, z);
 		}
 		return Material.air;
 	}
-	
+
 	@Override
 	public int getBlockMetadata(int x, int y, int z) { // RenderBlocks で使用
 		BlockData data = getBlockData(x, y, z);
 		}
 		return 0;
 	}
-	
+
 	@Override
 	public TileEntity getBlockTileEntity(int x, int y, int z) { // 未使用
 		throw new UnsupportedOperationException("method not implemented");
 	}
-	
+
 	@Override
 	public float getBrightness(int x, int y, int z, int var4) { // RenderBlocks で使用
 		return 0;
 	}
-	
+
 	public List<BlockData> getCustomRenderBlocks() {
 		return customRenderBlocks;
 	}
-	
+
 	@Override
 	public int getHeight() { // RenderBlocks で使用
 		return parent.getHeight();
 	}
-	
+
 	@Override
 	public float getLightBrightness(int x, int y, int z) { // RenderBlocks で使用
 		return parent.provider.lightBrightnessTable[15]; // TODO 15をもっと賢く
 	}
-	
+
 	@Override
 	public int getLightBrightnessForSkyBlocks(int x, int y, int z, int limit) { // RenderBlocks で使用
 		int skyBrightness = 15;
 		int blockBrightness = 13;
 		return skyBrightness << 20 | blockBrightness << 4;
 	}
-	
+
 	public List<BlockData> getSemiSurfaceBlocks() {
 		return semiSurfaceBlocks;
 	}
-	
+
 	public List<BlockData> getSurfaceBlocks() {
 		return surfaceBlocks;
 	}
-	
+
 	public NBTTagCompound getTileEntityData(Coord3D absPos) {
 		return allTileData.get(absPos);
 	}
-	
+
 	@Override
 	public Vec3Pool getWorldVec3Pool() { // RenderBlocks で使用
 		return parent.getWorldVec3Pool();
 	}
-	
+
 	@Override
 	public boolean isAirBlock(int x, int y, int z) { // RenderBlocks で使用
 		return this.getBlockId(x, y, z) == 0;
 	}
-	
+
 	@Override
 	public boolean isBlockNormalCube(int x, int y, int z) { // RenderBlocks で使用
 		return Block.isNormalCube(this.getBlockId(x, y, z));
 	}
-	
+
 	@Override
 	public boolean isBlockOpaqueCube(int x, int y, int z) { // RenderBlocks で使用
 		BlockData data = getBlockData(x, y, z);
 		}
 		return false;
 	}
-	
+
 	@Override
 	public int isBlockProvidingPowerTo(int x, int y, int z, int direction) { // 未使用
 		BlockData data = getBlockData(x, y, z);
 		}
 		return 0; // デフォルト
 	}
-	
+