6. díl - Minecraft Modding - Teleport 2. část

Java Minecraft Modding Minecraft Modding - Teleport 2. část

Pokračujeme ve třídě Ovladače Na začátek si překryjeme metodu onItemUse(), která je volána při kliknutí pravým tlačítkem na nějaký block.

public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int side, float fx, float fy, float fz)

Nejprve si zjistíme, zdali klikáme na BlockSaltPort:

if (world.getBlock(x, y, z) instanceof BlockSaltPort){
        if(!itemstack.hasTagCompound())
                itemstack.stackTagCompound = new NBTTagCompound();

Dále musíme zjistit, zdali má náš ovladač NBT, protože sice každý ItemStack má atribut NBT, ale pouze ten kdo ho potřebuje, si do něj uloží instance NBT. Musíme tedy do atributu přidat novou instanci NBT, jinak bychom pracovali s null. Teď si musíme načíst všechny atributy našeho stackTagCompound.

int xq = itemstack.stackTagCompound.getInteger("x");
int yq = itemstack.stackTagCompound.getInteger("y");
int zq = itemstack.stackTagCompound.getInteger("z");
boolean MamData = itemstack.stackTagCompound.getBoolean("MamData");

Sice máte pravdu, že čteme něco, co ještě nebylo vůbec vloženo, ale NBT nám vrátí 0,0,0 a false a s tím se dá pracovat. Zde je důležitý tag MamData, který vrací false v připadě kliknutí na první block a true na druhý. Ukládání 1. blocku do NBT bude vypadat takto:

if(!MamData){
        MamData=true;
        this.writeToNBT(x,y, z, MamData, itemstack);//Save
        world.playSoundAtEntity(player, "minecraft:random.click", 1F, 1F);//Sounds
        return true;
}

Nejprve se zeptáme, zda klikáme na 1. block. Pokud ano, nastavíme MamData na true (aby se nám při kliku na 2. block již tento blok kodu nespustil). Poté použijeme metodu deklarovanou v minulém díle writeToNBT() a uložíme souřadnice 1. blocku. Nakonec přehrajeme zvuk kliknutí, aby hráč věděl, že ten item něco opravdu dělá. Vracíme true, protože náš item něco dělá. Nyní přijde ta těžší část, a to vytvoření nového spojení. Pro přehlednost vytvoření NBT uzlů poslouží tento graf.

Ve WorldSavedData respektive ve MyWorldData je atribut NBTTagCompound. Do něho přidáme tag typu NBTTagCompound a jménem "Teleport Management". Do něj budeme přidávat další NBTTagCompound tagy se jménem ID, což je unikátní jméno každého spojení, přes které se k tomuto spojení bude přistupovat. A toto spojení bude mít 3 další tagy: int[], int[], int.

if(MamData){
        int[] l1={xq,yq,zq}; //souřadnice 1. blocku
        int[] l2 = {x,y,z};  //souřadnice 2. blocku
        if(l1!=l2){          //pokud neklikám na ten samý block podruhé

                NBTTagCompound worldnbt = MyWorldData.forWorld(world).tag;//získám MyWorldData pro tento svět a jeho NBT tag

                worldnbt.setTag(TELEMANAGE, worldnbt.getCompoundTag(TELEMANAGE));

Možná se vám zdá předchozí řádek naprosto zbytečný. Avšak toto řešení má svou logiku: Pokud chceme získat NBT tag z NBT tagu, který neexistuje, vrátí nám new NBTTagCompound(). Pokud existuje, jednoduše tam nahrajeme již existující tag, pokud ne, uložíme tam novou instanci NBT.

NBTTagCompound tm = worldnbt.getCompoundTag(TELEMANAGE);
NBTTagCompound spojeni= new NBTTagCompound();//nový tag spojení
spojeni.setIntArray(L1, l1);//uložení obou lokací blocků pomocí finálních Stringů L1, L2
spojeni.setIntArray(L2, l2);
tm.setInteger(PORADI, tm.getInteger(PORADI)+1);//nový tag do telemanage nebo již existující zvětšený o jedna. Užit ke zjištění jaké ID bude mít další spojení
tm.setTag("Spojeni"+tm.getInteger(PORADI), spojeni);//uložíme do telemanage naše spojení s ID=klíčem: "Spojeni"+poradi

MyWorldData.forWorld(world).markDirty();

Metoda markDirty() znamená v překladu ušpinit. Pokud označíme objekt metodou markDirty(), Minecraft v nejbližší době zavolá metodu writeToNBT(), čímž zajistí uložení.

BlockSaltPort b=(BlockSaltPort) world.getBlock(x, y, z);//získáme nějaký blockSaltPort

b.setTransportID(world,x,y,z,tm.getInteger(PORADI)); //nastavení metadat 2. blocku
b.setTransportID(world,xq,yq,zq,tm.getInteger(PORADI)); //nastavení metadat 1. blocku

this.writeToNBT(0, 0, 0, false, itemstack);//nakonec vynulujeme náš ovladač.
world.playSoundAtEntity(player, "minecraft:random.click", 1F, 1F);

}
}

SaltPortBlock

Pro reakci na kliknutí pravým tlačítkem na block slouží metoda:

public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float fx, float fy, float fz)

Nejprve zjistíme, jestli je hráč na blocku:

if(player.onGround && (int)player.posX == x|| (int)player.posX == x+1||(int)player.posX == x-1 && player.posY==y+1 && (int)player.posZ==z||(int)player.posZ==z+1||(int)player.posZ==z-1) {
                                port(world, player,x,y,z,world.getBlockMetadata(x, y, z));
                                return true;
                        }
                return false;

Zde použijeme zatím neexistující metodu port, která má za parametry World, Player, souřadnice tohoto blocku a metadata tohoto blocku, které budou použity pro zjištění ID spojení.

public void port(World world, EntityPlayer player,int x,int y,int z, int meta)
        {
                try{//vyhodí výjimku, pokud NBT bude new NBT() bez atributu ke kterému přistupujeme
                                  NBTTagCompound teleportation = MyWorldData.forWorld(world).tag.getCompoundTag(ItemPortRemote.TELEMANAGE).getCompoundTag("Spojeni"+meta);//získání spojení pomocí metadat
                        int[] location = {x,y,z};//vytvoření pole ze souřadnic blocku

Protože ve spojení jsou uložené 2 souřadnice blocků a my nevíme, jaké souřadnice použít jako lokaci k teleportu, zjistíme, jestli první souřadnice ze spojení jsou shodné se souřadnice tohoto blocku. Pokud jsou, použijeme k teleportu tyto 2. souřadnice, jinak použijeme první.

if(Arrays.equals(location, teleportation.getIntArray(ItemPortRemote.L1)))

        location = teleportation.getIntArray(ItemPortRemote.L2);
else
        location = teleportation.getIntArray(ItemPortRemote.L1);

          EntityPlayerMP player1 = (EntityPlayerMP)player;//Specialní instance hráče
      player1.playerNetServerHandler.setPlayerLocation(location[0] +0.5D, location[1]+1, location[2] +0.5D, player1.rotationYaw, player1.rotationPitch);//vlastní port
      world.playSoundAtEntity(player, "minecraft:mob.endermen.portal", 0.3F, 0.3F);

  }
  catch(Exception e){
          //Neexistuje telespojeni s this.id
          this.removeTeleInfo(world,x,y,z);
  }
}

Asi jste si všimli metody removeTeleInfo(). Ještě jsem nezmínil jeden problém, a to vymazání spojení. To bude žádoucí ve dvou případech:

  1. při rozbití blocku = aby hráč nebyl portován tam, kde tele-block není.
  2. při změně metadat = když pomocí ovladače propojíme již spojený block s jiným, 3. block by portoval na 1. block, ale 1. by portoval na 2. a 2. port na 1.

Při těchto eventech bude nutno vymazat spojení, a k tomu bude sloužit tato metoda:

public void removeTeleInfo(World w,int x,int y,int z){
                        int removedmeta=w.getBlockMetadata(x, y, z);
                        if(w.getBlockMetadata(x, y, z)!=0){//pokud má tento block nějaké spojení
                          MyWorldData.forWorld(w).tag.getCompoundTag(ItemPortRemote.TELEMANAGE).setTag("Spojeni"+removedmeta, null);//odstranění tagu spojení
                          w.setBlockMetadataWithNotify(x, y, z, 0, 2);//nastavení metadat na 0 = block nemá spojení
                          MyWorldData.forWorld(w).markDirty();//uložíme NBT
                        }

                }

Tuto metodu budeme volat z dalších těchto metod:

public void onBlockDestroyedByExplosion(World w, int x, int y, int z, Explosion ex){
                removeTeleInfo(w,x,y,z);
        }

         public boolean removedByPlayer(World w, EntityPlayer player, int x, int y, int z)
            {
                        removeTeleInfo(w,x,y,z);

                return w.setBlockToAir(x, y, z);//postaráme se o správnou fce této metody (koukněte na removedByPlayer() ve třídě Block)
            }

A nakonec poslední metoda, kterou jsme volali při tvoření spojení z ovladače:

public void setTransportID(World w,int x,int y,int z,int meta){
                         this.removeTeleInfo(w,x,y,z);
                         w.setBlockMetadataWithNotify(x, y, z, meta, 2);
                 }

Tato metoda uloží na souřadnice blocku metadata, ale ještě předtím zavolá metodu removeTeleInfo(), která se postará o zrušení NBT spojení (pokud nějaké existuje).

Finále

Tímto jsme dodělali všechny tři třídy:

  1. MyWorldData, patří Worldu a uchovává NBT tag pro náš Teleportační systém.
  2. ItemPortRemote ovladač, který slouží k vytváření spojení mezi dvěma blocky a jeho uložení do MyWorldData.
  3. BlockSaltPort, načte své spojení z Teleportačního systému pomocí uloženého meta a portuje hráče na 2. block ve spojení. Vymaže své spojení z Tele-systému, pokud je odstraněn nebo pokud mu je přiděleno nové spojení.

Jelikož mám z tohoto módu opravdu radost, dovolím si ještě popsat funkčnost:

Nejprve položím dva port-blocky do světa (je jedno v jakém jsou chunku, vzdálenost zde nehraje žádnou roli). Vezmu si ovladač a pravým tlačítkem kliknu na 1. block. Ovladač cvakne, doběhnu k 2. blocku a zopakuji postup. Teď, když kliknu pravým tlačítkem na první či druhý block, portne mě to na ten druhý. Pokud teď jeden block odstraním a pokusím se kliknout na druhý, nic se nestane (spojení bylo vymazáno). Uvedu vše do původní podoby, postavím tedy dva bloky a propojím je pomocí ovladače. Nyní položím třetí block, který hned propojím s prvním blockem. Tyto dva blocky (1. a 3.) nyní fungují a druhý block, kterému bylo vymazáno spojení, ne.

A to je konec tohoto dílu se dvěma částmi. Naučili jsme se zde, jak uložit data zaprvé do itemu (NBT), zadruhé do blocku (meta) a zatřetí do worldu (WorldSavedDa­ta+NBT).

Pokud něco nechápete, či jsem to špatně vysvětlil, určitě napište komentář. Celý zdrojový kód napsaný za tyto dva díly je ke stáhnutí pod článkem. (obsahující MyWorldData, ItemPortRemote a BlockSaltPort)


 

Stáhnout

Staženo 8x (8.51 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

  Aktivity (1)

Článek pro vás napsal Matěj Černý
Avatar
Autor se věnuje programování v Javě, moduje Java hru Minecraft a pracuje se Cinema4D.

Jak se ti líbí článek?
Celkem (4 hlasů) :
4.54.54.54.54.5


 


Miniatura
Všechny články v sekci
Minecraft Modding

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!