[1.7.10]当风过时的GUI教程(三)

By | 2015年7月17日

上一个教程已经将整个Block的逻辑搭建好了,最后就是服务端与客户端同步的问题,Minecraft单机是会创建一个伪服务端,而GUI的描绘部分则是客户端的事情,客户端需要服务端提供正确的数据才能正确的描绘数据的状态。Container就是负责同步服务端数据与客户端GUI的组件了。

先修改GUI文件中的drawGuiContainerBackgroundLayer,令其可以根据TileEntity的燃烧值描燃烧进度

@Override
	protected void drawGuiContainerBackgroundLayer(float var1, int var2,
			int var3) {
		// TODO Auto-generated method stub
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        this.mc.renderEngine.bindTexture(new ResourceLocation("newmod","textures/gui/RepairTable.png"));
        int var5 = (this.width - this.xSize) / 2;
        int var6 = (this.height - this.ySize) / 2;
        this.drawTexturedModalRect(var5, var6, 0, 0, this.xSize, this.ySize);
     // 下面是新增的东西
        int b = tile.tableBurnTime; // 取得Tile内的燃料燃烧时间
        float maxBurnTime = tile.maxBurnTime*1.0F;// 取得最大燃料燃烧时间,用float,不用的话得不出百分比
        if (b > 0 && maxBurnTime > 0) // 确定描绘的时机
        {
                // 描绘火焰图像
            this.drawTexturedModalRect(this.guiLeft + 81, this.guiTop + 37 + (int)(14 - 14 * ((float)b / maxBurnTime)), 176, (int)(14 - 14 * ((float)b / maxBurnTime)), 14, (int)(14 * ((float)b / maxBurnTime)));
        }
	}

这里取得的TileEntity的燃烧值是客户端最后接收到服务端数据的值,通过燃烧值/最大燃烧值的比值计算出需要描绘的图标百分比,至于怎么描绘第一章已经讲有了,因为不知道什么时候会发生客户端同步服务端,所以会出现进度条闪动的情况,这时就需要让Container进行同步了。

@Override
	public void addCraftingToCrafters(ICrafting par1iCrafting) {
		// TODO Auto-generated method stub
		super.addCraftingToCrafters(par1iCrafting);
		par1iCrafting.sendProgressBarUpdate(this, 0, this.tile.tableBurnTime);
		par1iCrafting.sendProgressBarUpdate(this, 1, this.tile.maxBurnTime);
	}
 
	@SideOnly(Side.CLIENT)
	public void updateProgressBar(int par1, int par2) {
		if (par1 == 0) {
			this.tile.tableBurnTime = par2;
		}
		if (par1 == 1) {
			this.tile.maxBurnTime = par2;
		}
	}
 
	@Override
	public void detectAndSendChanges() {
		// TODO Auto-generated method stub
		super.detectAndSendChanges();
		Iterator var1 = this.crafters.iterator();
		while (var1.hasNext()) {
			ICrafting var2 = (ICrafting) var1.next();
 
			if (this.lastTableBurnTime != this.tile.tableBurnTime) {
				var2.sendProgressBarUpdate(this, 0, this.tile.tableBurnTime);
			}
 
			if (this.lastMaxBurnTime != this.tile.maxBurnTime) {
				var2.sendProgressBarUpdate(this, 1, this.tile.maxBurnTime);
			}
		}
		this.lastTableBurnTime = this.tile.tableBurnTime;
		this.lastMaxBurnTime = this.tile.maxBurnTime;
	}

addCraftingToCrafters是添加监视器初始化的函数,监听数据变动的,用ICrafting进行注册,sendProgressBarUpdate就是将服务器上的数据发送给客户端第一个参数为Container本身,第二个是识别的ID,第三个是数据。

updateProgressBar是客户端取得数据后进行同步的函数返回的第一个参数是ID,第二个是要同步的数据。

detectAndSendChanges是服务端发送数据的函数,当服务端上发现数据有变化时,就会将数据变化后的数据发送给客户端。

完成上述步骤后整个GUI就可以正常工作了。

最后给GUI添加一个Shift键移动物品的功能,实现这个功能需要重写Container中的transferStackInSlot:

@Override
	public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2) {
		ItemStack var3 = null;
		Slot var4 = (Slot) this.inventorySlots.get(par2);
		if (var4 != null && var4.getHasStack()) {
			ItemStack var5 = var4.getStack();
			var3 = var5.copy();
			// 点击到Slot的ID为0-2之间的时候,将物品送回玩家的背包中
			if (par2 >= 0 && par2 <= 2) {
				if (!this.mergeItemStack(var5, 3, 30, false)) {
					return null;
				}
				var4.onSlotChange(var5, var3);
			}
			// 点击到玩家的背包的时候将物品送到玩家的快捷栏中
			else if (par2 > 3 && par2 < 30) {
				if (!this.mergeItemStack(var5, 30, 39, false)) {
					return null;
				}
			}
			// 点击到玩家的快捷栏的时候将物品送到背包中
			else if (par2 >= 30 && par2 < 39) {
				if (!this.mergeItemStack(var5, 3, 30, false)) {
					return null;
				}
			}
			if (var5.stackSize == 0) {
				var4.putStack((ItemStack) null);
			} else {
				var4.onSlotChanged();
			}
			if (var5.stackSize == var3.stackSize) {
				return null;
			}
			var4.onPickupFromSlot(par1EntityPlayer, var5);
		}
		return var3;
	}

mergeItemStack是传送物品栈的函数,它能将物品栈传送到指定的ID范围内,第一个参数物品栈,第二个是被传送到的起始ID,第三个是被传送 到的结束ID,第四个是正序或逆序传送(就是优先从开头数还是从末尾数起)。这个的ID范围没设定好的话很容易造成复制物品的bug。

基础的Block GUI教程就是这么多了。GUI还有一些其他的用法,有闲心的话我再继续写写。

第四篇关于无TileEntity GUI教程编写中

全部的源码:http://pan.baidu.com/s/1sjwr4wX

本文链接地址:http://blog.windworkshop.net/?p=440 »文章允许转载 ,转载请注明出处,谢谢。

[1.7.10]当风过时的GUI教程(三)” 的评论

  1. _xiaoe

    大大 请问如何实现上方漏斗像slot0输入 下方漏斗接受slot1的输出

    回复
    1. 当风过时 文章作者

      这个研究不多,大致知道是通过ISidedInventory接口的getAccessibleSlotsFromSide函数返回特定Slot位置的index,getAccessibleSlotsFromSide送入的参数决定需要返回的输入输出Slot的index,详见TileEntityFurnace和TileEntityHopper

      回复
  2. _xiaoe

    大大 我写的一个tileentity 当要写入NBT时报错。。
    [11:23:55] [Server thread/ERROR] [FML]: A TileEntity type xiaoe.TheBuilder.gui.TileMaker_TitleEntity has throw an exception trying to write state. It will not persist. Report this to the mod author
    java.lang.RuntimeException: class xiaoe.TheBuilder.gui.TileMaker_TitleEntity is missing a mapping! This is a bug!
    at net.minecraft.tileentity.TileEntity.writeToNBT(TileEntity.java:96) ~[TileEntity.class:?]
    at xiaoe.TheBuilder.gui.TileMaker_TitleEntity.writeToNBT(TileMaker_TitleEntity.java:90) ~[TileMaker_TitleEntity.class:?]
    at net.minecraft.world.chunk.storage.AnvilChunkLoader.writeChunkToNBT(AnvilChunkLoader.java:395) [AnvilChunkLoader.class:?]
    at net.minecraft.world.chunk.storage.AnvilChunkLoader.saveChunk(AnvilChunkLoader.java:204) [AnvilChunkLoader.class:?]
    at net.minecraft.world.gen.ChunkProviderServer.safeSaveChunk(ChunkProviderServer.java:287) [ChunkProviderServer.class:?]
    at net.minecraft.world.gen.ChunkProviderServer.saveChunks(ChunkProviderServer.java:340) [ChunkProviderServer.class:?]
    at net.minecraft.world.WorldServer.saveAllChunks(WorldServer.java:863) [WorldServer.class:?]
    at net.minecraft.server.MinecraftServer.saveAllWorlds(MinecraftServer.java:370) [MinecraftServer.class:?]
    at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:636) [MinecraftServer.class:?]
    at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [IntegratedServer.class:?]
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:485) [MinecraftServer.class:?]
    at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:752) [MinecraftServer$2.class:?]

    回复
  3. 暮光小猿wzt

    都不说每个语句是起什么作用,哪个参数是干什么的..只能是猜

    回复
    1. 当风过时 文章作者

      只打算说明关键部分和相关的运行原理,其他的没打注释要么就是系统带的不方便进行修改或者没有太大必要进行修改的,要么就是给制作者自己发挥想象空间的地方,真要理解的可以去下载源码配合每一段的说明随手改一下看看运行结果基本也能弄个八九不离十。

      回复
  4. 潘彬彬

    (net.minecraft.server.integrated.IntegratedServer@42db8904)
    [22:36:21] [Server thread/INFO] [FML]: Loading dimension 1 (2016) (net.minecraft.server.integrated.IntegratedServer@42db8904)
    [22:36:21] [Server thread/INFO] [FML]: Loading dimension -1 (2016) (net.minecraft.server.integrated.IntegratedServer@42db8904)
    [22:36:21] [Server thread/INFO]: Preparing start region for level 0
    [22:36:22] [Server thread/INFO] [STDOUT]: [cubex2.mods.morefurnaces.tileentity.TileEntityIronFurnace:readFromNBT:133]: ================iron read================
    [22:36:22] [Server thread/INFO]: Changing view distance to 12, from 10
    [22:36:23] [Netty Client IO #0/INFO] [FML]: Server protocol version 1
    [22:36:23] [Netty IO #1/INFO] [FML]: Client protocol version 1
    [22:36:23] [Netty IO #1/INFO] [FML]: Client attempting to join with 6 mods : RepairTable@1.0,FML@7.10.85.1222,Forge@10.13.1.1222,mcp@9.05,MoreFurnaces@1.3.9,newmod@1.0
    [22:36:23] [Netty IO #1/INFO] [FML]: Attempting connection with missing mods [] at CLIENT
    [22:36:23] [Netty Client IO #0/INFO] [FML]: Attempting connection with missing mods [] at SERVER
    [22:36:23] [Server thread/INFO] [FML]: [Server thread] Server side modded connection established
    [22:36:23] [Client thread/INFO] [FML]: [Client thread] Client side modded connection established
    [22:36:23] [Server thread/INFO]: Player251[local:E:33cf6f6b] logged in with entity id 86 at (556.5539476782021, 22.0, 1487.4642776996898)
    [22:36:23] [Server thread/INFO]: Player251 joined the game
    [22:36:23] [Server thread/INFO] [STDOUT]: [cubex2.mods.morefurnaces.tileentity.TileEntityIronFurnace:writeToNBT:167]: ================iron write================
    [22:36:24] [Client thread/INFO] [STDOUT]: [cubex2.mods.morefurnaces.tileentity.TileEntityIronFurnace:readFromNBT:133]: ================iron read================
    [22:36:31] [Server thread/INFO]: Saving and pausing game…
    [22:36:31] [Server thread/INFO]: Saving chunks for level ‘2016’/Overworld
    [22:36:31] [Server thread/INFO] [STDOUT]: [combine.TileEntityRepairTable:writeToNBT:403]: ================re write================
    [22:36:31] [Server thread/INFO]: Saving chunks for level ‘2016’/Nether
    [22:36:31] [Server thread/INFO]: Saving chunks for level ‘2016’/The End

    iron 是其他mod的nbt读取,re是我的mod ,为何我的只有在暂停时才出现一个write,iron在进入世界后都能读取nbt,我的re不行。。。。求教

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据