IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Mezi 13:00 až cca 16:00 proběhne odstávka sítě z důvodu aktualizace. Web bude po celou dobu nedostupný.

Lekce 6 - Minecraft Modding - Teleport 2. část

V předchozí lekci, Minecraft Modding - Teleport 1. část, jsme si vysvětlili NBT TagCompound, Block Metadata, WorldSavedData a vytvořili jsme Teleport systému.

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.

Minecraft Modding

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)

V další lekci, Minecraft Modding - ItemFood, Potion s EventHook, si vytvoříme item salát.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

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

 

Předchozí článek
Minecraft Modding - Teleport 1. část
Všechny články v sekci
Minecraft Modding
Přeskočit článek
(nedoporučujeme)
Minecraft Modding - ItemFood, Potion s EventHook
Článek pro vás napsal Matěj Černý
Avatar
Uživatelské hodnocení:
5 hlasů
Autor se věnuje programování v Javě, C++, zajímá se o OpenGL.
Aktivity