3
0

模块化方块捕获还原动作

This commit is contained in:
2017-07-04 14:29:35 +08:00
parent 559b9ad248
commit bfe43ae465
12 changed files with 992 additions and 402 deletions

View File

@ -0,0 +1,40 @@
package cc;
import net.minecraft.world.World;
public class Location{
public World mWorld;
public int mPosX=0;
public int mPosY=0;
public int mPosZ=0;
private String mToString=null;
public Location(World pWorld,int pPosX,int pPosY,int pPosZ){
this.mWorld=pWorld;
this.mPosX=pPosX;
this.mPosY=pPosY;
this.mPosZ=pPosZ;
}
@Override
public String toString(){
if(this.mToString==null){
this.mToString=this.mWorld.worldInfo.getWorldName()+"("+this.mPosX+","+this.mPosY+","+this.mPosZ+")";
}
return this.mToString;
}
@Override
public int hashCode(){
return this.toString().hashCode();
}
@Override
public boolean equals(Object pObj){
return pObj instanceof Location&&((Location)pObj).hashCode()==this.hashCode();
}
}

View File

@ -0,0 +1,38 @@
package cc.capture;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
public class ItemSnapshot{
public final EntityPlayer mPlayer;
public final ItemStack mItem;
private boolean mApply=false;
public ItemSnapshot(EntityPlayer pPlayer,ItemStack pItem){
this.mPlayer=pPlayer;
this.mItem=pItem;
}
/**
* 将物品放到玩家身上
*
* @return 如果背包满,将生成物品在地上并返回false
*/
public boolean apply(){
if(!this.mApply){
this.mApply=true;
this.mPlayer.inventory.addItemStackToInventory(this.mItem);
if(!this.mPlayer.inventory.addItemStackToInventory(this.mItem)){
this.mPlayer.worldObj.spawnEntityInWorld(
new EntityItem(this.mPlayer.worldObj,this.mPlayer.posX,this.mPlayer.posY,this.mPlayer.posZ,this.mItem));
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,171 @@
package cc.capture;
import java.util.Iterator;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import cc.capture.type.ACapture;
import cc.capture.type.CaptureBlock;
import cc.capture.type.CaptureTree;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class WorldCapture{
public final World mWorld;
/** Capture任务Id生成器 */
private AtomicInteger mIdCreate=new AtomicInteger();
/** 方块捕获任务 */
public Stack<CaptureBlock> mBlockCaptures=new Stack<CaptureBlock>();
/** 树捕获任务 */
public Stack<CaptureTree> mTreeCaptures=new Stack<CaptureTree>();
public WorldCapture(World pWorld){
this.mWorld=pWorld;
}
public CaptureBlock getLastBlockCapture(){
return getEleOrLast(this.mBlockCaptures,-1);
}
public CaptureTree getLastTreeGenCapture(){
return getEleOrLast(this.mTreeCaptures,-1);
}
public static <T extends ACapture> T getEleOrLast(Stack<T> pStack,int pId){
if(pId!=-1){
Iterator<T> tIt=pStack.iterator();
while(tIt.hasNext()){
T tCapture=tIt.next();
if(tCapture.mHandled){
tIt.remove();
}else if(tCapture.mId==pId){
return tCapture;
}
}
}
while(!pStack.isEmpty()){
T tCapture=pStack.lastElement();
if(tCapture.mHandled){
pStack.pop();
}
return tCapture;
}
return null;
}
public void addCaptureEntity(World pWorld,Entity pEntity,SpawnReason pReason){
CaptureBlock tCapture=this.getLastBlockCapture();
if(tCapture==null||!tCapture.mEnable) return;
tCapture.addCaptureEntity(pWorld,pEntity,pReason);
}
public void addCaptureItem(EntityPlayer pPlayer,ItemStack pItem){
CaptureBlock tCapture=this.getLastBlockCapture();
if(tCapture==null||!tCapture.mEnable) return;
tCapture.addCaptureItem(pPlayer,pItem);
}
public void addCheckedBlock(World pWorld,int pPosX,int pPosY,int pPosZ){
CaptureBlock tCapture=this.getLastBlockCapture();
if(tCapture==null||!tCapture.mEnable) return;
tCapture.addCheckedBlock(pWorld,pPosX,pPosY,pPosZ);
}
public boolean isCapture(){
CaptureBlock tCapture=this.getLastBlockCapture();
return tCapture!=null&&tCapture.mEnable;
}
public boolean isTreeGenCapture(){
CaptureTree tCapture=this.getLastTreeGenCapture();
return tCapture!=null&&tCapture.mEnable;
}
public CaptureBlock startCapture(EntityPlayer pPlayer){
ItemStack tItem=null;
int tSlot=-1;
if(pPlayer!=null){
tSlot=pPlayer.inventory.currentItem;
tItem=pPlayer.getCurrentEquippedItem();
}
return this.startCapture(pPlayer,tItem,tSlot);
}
public CaptureBlock startCapture(EntityPlayer pPlayer,ItemStack pCurrent){
return this.startCapture(pPlayer,pCurrent,-1);
}
public CaptureBlock startCapture(EntityPlayer pPlayer,ItemStack pCurrent,int pSlot){
CaptureBlock tCapture=this.mBlockCaptures.push(new CaptureBlock(this,this.mIdCreate.incrementAndGet(),pPlayer));
tCapture.mUseItem=pCurrent;
if(pCurrent!=null){
tCapture.mOldItemMeta=pCurrent.getItemDamage();
tCapture.mOldItemSize=pCurrent.stackSize;
tCapture.mOldItemNBT=pCurrent.stackTagCompound;
tCapture.mSlot=pSlot;
}
return tCapture;
}
public void disableCapture(){
CaptureBlock tCapture=this.getLastBlockCapture();
if(tCapture==null) return;
tCapture.mEnable=false;
}
public boolean endCapture(int pId){
CaptureBlock tCapture=getEleOrLast(this.mBlockCaptures,pId);
if(tCapture==null) return true;
this.mBlockCaptures.remove(tCapture);
return tCapture.endCapture();
}
public CaptureTree startTreeGenCapture(EntityPlayer pPlayer,int pPosX,int pPosY,int pPosZ){
CaptureTree tCapture=this.mTreeCaptures.push(new CaptureTree(this,this.mIdCreate.incrementAndGet(),pPlayer));
tCapture.setAgaistPostionAndSide(-1,pPosX,pPosY,pPosZ);
return tCapture;
}
public CaptureTree startTreeGenCapture(EntityPlayer pPlayer,org.bukkit.Location pTreeLoc){
return this.startTreeGenCapture(pPlayer,pTreeLoc.getBlockX(),pTreeLoc.getBlockY(),pTreeLoc.getBlockZ());
}
public CaptureTree disableTreeGenCapture(int pId){
CaptureTree tCapture=getEleOrLast(this.mTreeCaptures,pId);
if(tCapture==null) return null;
tCapture.mEnable=false;
return tCapture;
}
public boolean endTreeGenCapture(int pId){
CaptureTree tCapture=getEleOrLast(this.mTreeCaptures,pId);
if(tCapture==null) return true;
this.mTreeCaptures.remove(tCapture);
return tCapture.endCapture();
}
/**
* 清理捕获的数据
*/
public void clearAllData(){
this.mBlockCaptures.clear();
this.mTreeCaptures.clear();
}
}

View File

@ -0,0 +1,68 @@
package cc.capture.type;
import java.util.ArrayList;
import cc.capture.WorldCapture;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.common.util.ForgeDirection;
public abstract class ACapture{
public final WorldCapture mWorldCapture;
public final World mWorld;
public final int mId;
/** 是否启用捕获 */
public boolean mEnable=true;
/** 是否已经处理完毕 */
public boolean mHandled=false;
/** 当前捕获作用的玩家,可能为null,用作普通捕获 */
public final EntityPlayer mCapturePlayer;
/** 方块放置时顶着的面 */
protected ForgeDirection mSide=ForgeDirection.UNKNOWN;
protected Block mAgaistBlock=Blocks.air;
/** 捕获的数据 */
public ArrayList<BlockSnapshot> mCapturedBlocks=new ArrayList<BlockSnapshot>();
public ACapture(WorldCapture pWorldCapture,int pId,EntityPlayer pPlayer){
this.mWorldCapture=pWorldCapture;
this.mWorld=pWorldCapture.mWorld;
this.mId=pId;
this.mCapturePlayer=pPlayer;
}
public void setAgaistPostionAndSide(int pSide,int pPosX,int pPosY,int pPosZ){
this.mSide=ForgeDirection.getOrientation(pSide);
this.mAgaistBlock=this.mWorldCapture.mWorld.getBlock(pPosX,pPosY,pPosZ);
}
public void addCapturedBlock(World pWorld,int pPosX,int pPosY,int pPosZ){
this.addCapturedBlock(pWorld,pPosX,pPosY,pPosZ,3);
}
public void addCapturedBlock(World pWorld,int pPosX,int pPosY,int pPosZ,int pFlag){
if(!this.mEnable) return;
BlockSnapshot tSnapshot=BlockSnapshot.getBlockSnapshot(pWorld,pPosX,pPosY,pPosZ,pFlag);
this.mCapturedBlocks.add(tSnapshot);
}
public void disableCapture(){
this.mEnable=false;
}
/**
* 标记此捕获为已经处理
* <p>
* 只设置捕获中的数据,并从世界捕获中移除,不会清理捕获数据
* </p>
*/
public void markHandled(){
this.mEnable=false;
this.mHandled=true;
}
}

View File

@ -0,0 +1,154 @@
package cc.capture.type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import cc.Location;
import cc.capture.EntitySnapshot;
import cc.capture.ItemSnapshot;
import cc.capture.WorldCapture;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.stats.StatList;
import net.minecraft.world.World;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.world.BlockEvent.PlaceEvent;
public class CaptureBlock extends ACapture{
/** 是否为还原模式 */
public boolean mRestoring=false;
/** 当前物品 */
public ItemStack mUseItem=null;
/** 当前物品所在的快捷栏位置,如果为-1表示不存在,或者不是从背包取出的物品 */
public int mSlot=-1;
public int mOldItemSize=0;
public int mOldItemMeta=0;
public NBTTagCompound mOldItemNBT=null;
/** 捕获的数据 */
public ArrayList<EntitySnapshot> mCapturedEntitys=new ArrayList<EntitySnapshot>();
public ArrayList<ItemSnapshot> mCapturedItems=new ArrayList<ItemSnapshot>();
public ArrayList<Location> mCheckedBlocks=new ArrayList<Location>();
public CaptureBlock(WorldCapture pWorldCapture,int pId,EntityPlayer pPlayer){
super(pWorldCapture,pId,pPlayer);
}
@Override
public void markHandled(){
super.markHandled();
this.mWorldCapture.mBlockCaptures.remove(this);
}
@Override
public void addCapturedBlock(World pWorld,int pPosX,int pPosY,int pPosZ,int pFlag){
if(!this.mEnable||this.isChecked(pWorld,pPosX,pPosY,pPosZ,false))
return;
super.addCapturedBlock(pWorld,pPosX,pPosY,pPosZ,pFlag);
}
public void addCapturedBlock(BlockSnapshot pSnapshot){
if(!this.mEnable||this.isChecked(pSnapshot.world,pSnapshot.x,pSnapshot.y,pSnapshot.z,false))
return;
this.mCapturedBlocks.add(pSnapshot);
}
public boolean isChecked(World pWorld,int pPosX,int pPosY,int pPosZ,boolean pSimula){
if(!this.mCheckedBlocks.isEmpty()){
Iterator<Location> tIt=this.mCheckedBlocks.iterator();
while(tIt.hasNext()){
Location tLoc=tIt.next();
if(tLoc.mWorld==pWorld&&tLoc.mPosX==pPosX&&tLoc.mPosY==pPosY&&tLoc.mPosZ==pPosZ){
if(!pSimula) tIt.remove();
return true;
}
}
}
return false;
}
public void addCaptureEntity(World pWorld,Entity pEntity,SpawnReason pReason){
if(!this.mEnable) return;
this.mCapturedEntitys.add(new EntitySnapshot(pWorld,pEntity,pReason));
}
public void addCaptureItem(EntityPlayer pPlayer,ItemStack pItem){
if(!this.mEnable) return;
this.mCapturedItems.add(new ItemSnapshot(pPlayer,pItem));
}
public void addCheckedBlock(World pWorld,int pPosX,int pPosY,int pPosZ){
this.mCheckedBlocks.add(new Location(pWorld,pPosX,pPosY,pPosZ));
}
public boolean endCapture(){
if(this.mHandled) return true;
this.markHandled();
boolean tResult;
PlaceEvent tPlaceEvent=null;
if(this.mCapturedBlocks.size()>1){
tPlaceEvent=ForgeEventFactory.onPlayerMultiBlockPlace(this.mCapturePlayer,this.mCapturedBlocks,this.mSide);
}else if(this.mCapturedBlocks.size()==1){
tPlaceEvent=ForgeEventFactory.onPlayerBlockPlace(this.mCapturePlayer,this.mCapturedBlocks.get(0),this.mSide);
}
if(tPlaceEvent!=null&&(tPlaceEvent.isCanceled())){
if(this.mUseItem!=null){
if(this.mSlot==-1){
this.mUseItem.setItemDamage(this.mOldItemMeta);
this.mUseItem.stackSize=this.mOldItemSize;
this.mUseItem.setTagCompound(this.mOldItemNBT);
}else{
this.mCapturePlayer.inventory.setInventorySlotContents(this.mSlot,this.mUseItem);
}
}
if(!this.mCapturedBlocks.isEmpty()){
for(int i=this.mCapturedBlocks.size();i>0;){
this.mRestoring=true;
BlockSnapshot tSnapshot=this.mCapturedBlocks.get(--i);
tSnapshot.restore(true,false);
this.mRestoring=false;
}
}
for(EntitySnapshot sSnapshot : this.mCapturedEntitys){
sSnapshot.cancel();
}
tResult=false;
}else{
for(EntitySnapshot sSnapshot : this.mCapturedEntitys){
sSnapshot.apply();
}
if(!this.mCapturedItems.isEmpty()){
HashSet<EntityPlayer> tNotifyPlayers=new HashSet<EntityPlayer>();
for(ItemSnapshot sSnapshot : this.mCapturedItems){
if(sSnapshot.apply()){
tNotifyPlayers.add(sSnapshot.mPlayer);
}
}
for(EntityPlayer sPlayer : tNotifyPlayers){
sPlayer.openContainer.detectAndSendChanges();
}
}
if(this.mUseItem!=null&&this.mCapturePlayer!=null){
this.mCapturePlayer.addStat(StatList.objectUseStats[Item.getIdFromItem(this.mUseItem.getItem())],1);
}
tResult=true;
}
return tResult;
}
}

View File

@ -0,0 +1,72 @@
package cc.capture.type;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.TreeType;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.entity.Player;
import org.bukkit.event.world.StructureGrowEvent;
import cc.capture.WorldCapture;
import net.minecraft.block.BlockSapling;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.util.BlockSnapshot;
public class CaptureTree extends ACapture{
/** 捕获数模式下的位置 */
public org.bukkit.Location mTreeLoc=null;
public CaptureTree(WorldCapture pWorldCapture,int pId,EntityPlayer pPlayer){
super(pWorldCapture,pId,pPlayer);
}
@Override
public void setAgaistPostionAndSide(int pSide,int pPosX,int pPosY,int pPosZ){
super.setAgaistPostionAndSide(pSide,pPosX,pPosY,pPosZ);
this.mTreeLoc=new org.bukkit.Location(this.mWorld.getWorld(),(double)pPosX,(double)pPosY,(double)pPosZ);
}
@Override
public void markHandled(){
super.markHandled();
this.mWorldCapture.mTreeCaptures.remove(this);
}
public boolean endCapture(){
if(this.mHandled) return true;
this.markHandled();
boolean tResult=true;
if(this.mCapturedBlocks.size()>0)
return true;
TreeType tType=BlockSapling.treeType;
BlockSapling.treeType=null;
List<BlockState> tStates=new ArrayList();
for(BlockSnapshot sSnapshot : (List<BlockSnapshot>)this.mCapturedBlocks.clone()){
tStates.add(new CraftBlockState(sSnapshot));
}
StructureGrowEvent tEvent=null;
if(tType!=null){
tEvent=new StructureGrowEvent(this.mTreeLoc,tType,false,
this.mCapturePlayer==null?null:(Player)this.mCapturePlayer.getBukkitEntity(),tStates);
Bukkit.getPluginManager().callEvent(tEvent);
}
if(tEvent==null||!tEvent.isCancelled()){
for(BlockState sState : tStates){
sState.update(true);
}
tResult=true;
}
return tResult;
}
}

View File

@ -1,7 +1,5 @@
package org.bukkit.craftbukkit;
import gnu.trove.procedure.TObjectProcedure;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
@ -11,11 +9,6 @@ import java.util.Random;
import java.util.Set;
import java.util.UUID;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraftforge.common.util.BlockSnapshot;
import org.apache.commons.lang.Validate;
import org.bukkit.BlockChangeDelegate;
import org.bukkit.Bukkit;
@ -30,15 +23,74 @@ import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.craftbukkit.entity.*;
import org.bukkit.craftbukkit.entity.CraftItem;
import org.bukkit.craftbukkit.entity.CraftLightningStrike;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.metadata.BlockMetadataStore;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.util.LongHash;
import org.bukkit.entity.*;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Blaze;
import org.bukkit.entity.Boat;
import org.bukkit.entity.CaveSpider;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.ComplexLivingEntity;
import org.bukkit.entity.Cow;
import org.bukkit.entity.CreatureType;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Egg;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Giant;
import org.bukkit.entity.Golem;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Horse;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LeashHitch;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.MagmaCube;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Pig;
import org.bukkit.entity.PigZombie;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Silverfish;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.Slime;
import org.bukkit.entity.SmallFireball;
import org.bukkit.entity.Snowball;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.Spider;
import org.bukkit.entity.Squid;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownExpBottle;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Weather;
import org.bukkit.entity.Witch;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkull;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.Zombie;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.PoweredMinecart;
@ -56,7 +108,11 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.StandardMessenger;
import org.bukkit.util.Vector;
import cc.capture.type.CaptureTree;
import cpw.mods.fml.common.registry.EntityRegistry; // Cauldron
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.IEntityLivingData;
import net.minecraftforge.common.util.BlockSnapshot;
public class CraftWorld implements World {
//public static final int CUSTOM_DIMENSION_OFFSET = 10; // Cauldron - disabled
@ -512,13 +568,11 @@ public class CraftWorld implements World {
break;
}
world.captureTreeGeneration = true;
world.captureBlockSnapshots = true;
CaptureTree tCapture=world.mCapture.startTreeGenCapture(null,loc);
boolean grownTree = gen.generate(world, rand, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
world.captureBlockSnapshots = false;
world.captureTreeGeneration = false;
tCapture.markHandled();
if (grownTree) { // Copy block data to delegate
for (BlockSnapshot blocksnapshot : world.capturedBlockSnapshots) {
for (BlockSnapshot blocksnapshot : tCapture.mCapturedBlocks) {
int x = blocksnapshot.x;
int y = blocksnapshot.y;
int z = blocksnapshot.z;
@ -530,11 +584,9 @@ public class CraftWorld implements World {
net.minecraft.block.Block newBlock = world.getBlock(x, y, z);
world.markAndNotifyBlock(x, y, z, null, oldBlock, newBlock, flag);
}
world.capturedBlockSnapshots.clear();
return true;
}
else {
world.capturedBlockSnapshots.clear();
return false;
}
}