Witaj
Gość

Wątek: [Poradnik] Tworzenie instancji.  (Przeczytany 3750 razy)

  • Wiadomości: 643

  • Pochwał: 10

  • L2Cerberus/L2DC developer
    • L2Cerberus
[Poradnik] Tworzenie instancji.
« dnia: Wrzesień 04, 2010, 01:11:52 pm »
Tworzenie własnych instancji.
Poradnik robiłem na podstawie plików GE l2js.


1. Przygotowanie plików.

Na początek przygotujemy pliki które będą potrzebne, stworzymy pusty szablon i dodamy id naszej nowej instancji.



1.1 Drobna modyfikacja plików.

Zaczniemy od modyfikacji plików. Jako że tworzymy nową, własną instancję musimy dodać dla niej nowe unikalne id oraz nazwę, która będzie wyświetlana jako nazwa lokacji. Aby to zrobić otwieramy plik instancenames.xml w głównym katalogu datapack_development.



Przewijamy na sam dół pliku i dodajemy nowa linijkę z kolejnym id oraz naszą nazwą:

<instance id="134" name="Moja instancja" />



To tyle jeśli chodzi o edycję plików. Id zapamiętujemy ;)

1.2 Szablon pliku java pod instancje

Teraz tworzymy pusty szablon na naszą instancję. Lokacja pliku nie ma znaczenia, byle było to gdzieś wewnątrz katalogu scripts. Tworzymy pusty plik java. Umieszczamy wewnątrz poniższy kod. (nie ma tu raczej nic do tłumaczenia to tylko konstruktor + licencja)

/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package instances.WlasnaInstancja;

import com.l2jserver.gameserver.model.quest.Quest;
/**
 * @author InsOmnia
 */

public class WlasnaInstancja extends Quest
{
public WlasnaInstancja(int questId, String name, String descr)
{
super(questId, name, descr);
}

public static void main(String[] args)
{
new WlasnaInstancja(196, "WlasnaInstancja", "custom");
}
}

Oczywiście musicie zmienić nazwę instancji na waszą oraz deklaracje paczki, czyli lokalizację pliku. (ja użyłem nazwy "WlasnaInstancja").

1.3 Template dla instancji

Pozostało nam jeszcze stworzenie "template" instancji. Przechodzimy do katalogu data/instances, tworzymy tam pusty plik xml o nazwie takiej jak nasza instancja.



Wewnątrz umieszczamy:

Informacje dla parsera:

<?xml version="1.0" encoding="UTF-8"?>
Otwieramy znacznik instancji, w polu name umieszczamy nazwę którą podaliśmy w punkcie 1.1.1:

<instance name="Moja instancja">
Teraz dodajemy 4 podstawowe informacje o instancji,

activityTime - długość instancji w minutach,
emptyDestroyTime - czas po którym instancja się zamknie jeśli nikogo nie będzie wewnątrz (podawany w decysekundach, 1s = 10):
allowSummon - tutaj chyba jasne, zezwolenie na summonowanie wewnątrz instancji lub jego brak.
spawnPoint - lokalizacja do której przenoszona jest postać po zniszczeniu instancji, użyciu soe itd.

<activityTime val="60" />
<emptyDestroyTime val="3000" />
<allowSummon val="false" />
<spawnPoint spawnX="-80666" spawnY="151321" spawnZ="-3040" />

Zamykamy znacznik instancji:

</instance>
Całość:

<?xml version="1.0" encoding="UTF-8"?>
<instance name="Moja instancja">
<activityTime val="60" />
<emptyDestroyTime val="3000" />
<allowSummon val="false" />
<spawnPoint spawnX="-80666" spawnY="151321" spawnZ="-3040" />
</instance>



2. Tworzenie głównych metod.

Musimy stworzyć główne metody które będą obsługiwać instancje, czyli tworzenie instancji, teleport gracza.



2.1 Metoda "teleportPlayer".

Na początku deklarujemy zmienna, która przechowuję cords do teleportu. Zaraz poniżej

public class WlasnaInstancja extends Quest
wpisujemy:

private static final int[] enterCords = { 1, 2, 3 };
oczywiście podajemy tutaj lokalizacje do której gracz ma się teleportować.

Teraz sama metoda, pozwolę sobie ją pierwsze tutaj umieścić, a potem opisze.

private static final void teleportPlayer(L2PcInstance player, int[] coords, int instanceId)
{
player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
        player.setInstanceId(instanceId);
player.teleToLocation(coords[0], coords[1], coords[2], false);
}

Może opis deklaracji klas pominę w tym poradniku, nie jest on o tym, więc przejdę do argumentów metody. Pierwszy argument to oczywiście gracz który ma być teleportowany, drugi to lokalizacja, czyli nasze enterCords, trzeci argument to dynamiczne id instancji. Zmiana AI na IDLE jest tu umieszczona żeby uniknąć kilku exploitów oraz dziwnego zachowania petów wewnątrz. Poniżej zmieniamy świat gracza i teleportujemy go do ustalonego powyżej miejsca.

2.2 Metoda "enterInstance".

Najważniejsza metoda w naszym skrypcie, jest wiele sposobów jej realizacji, jednak ten który podam moim zdaniem jest najlepszy, najbardziej stabilny i nigdy nie powoduje problemów (używam go w każdej instancji i nie miałem jeszcze ani jednego przypadku jakiegoś błędu związanego z ta metodą).

Zaraz obok zmiennej enterCords, dodajemy zmienna przechowująca id instancji, to id które sami przyznaliśmy w instancenames.xml.

private static final int INSTANCE_ID = 134;
Teraz metoda główna, potem jej opis:

private synchronized void enterInstance(L2PcInstance player)
{
InstanceWorld world = InstanceManager.getInstance().getPlayerWorld(player);
if (world != null)
{
if (world.templateId != INSTANCE_ID)
{
player.sendPacket(new SystemMessage(SystemMessageId.ALREADY_ENTERED_ANOTHER_INSTANCE_CANT_ENTER));
return;
}
Instance inst = InstanceManager.getInstance().getInstance(world.instanceId);
if (inst != null)
teleportPlayer(player, enterCords, world.instanceId);
return;
}
else
{
final int instanceId = InstanceManager.getInstance().createDynamicInstance("WlasnaInstancja.xml");
world = InstanceManager.getInstance().new InstanceWorld();
world.instanceId = instanceId;
world.templateId = INSTANCE_ID;
InstanceManager.getInstance().addWorld(world);
_log.info("WlasnaInstancja: started instance: " +instanceId + " created by player: " + player.getName());
world.allowed.add(player.getObjectId());
teleportPlayer(player, enterCords, instanceId);
}
}

Dlaczego synchronized? Wymagany jest tutaj kolejkowy dostęp do metody, bez niego może się zdarzyć że tworzone są 2 instancje w tym samym momencie co powoduje wymieszanie zmiennych i gracze przenoszeni są do pustego świata.
Teraz wnętrze metody. Pierwsze pobieramy istniejącą instancje gracza, jeśli taka istnieje sprawdzamy czy jest to właśnie ta instancja do której chcemy wejść, czy inna, jeśli inna, wysyłamy komunikat że gracz już ma stworzoną inna instancje. Natomiast jeśli jest to nasza instancja, sprawdzamy po raz kolejny czy istnieje (mogła zostać zamknięta), a następnie teleportujemy tam gracza.
Teraz druga opcja całej metody, gracz nie ma stworzonej żadnej instancji, więc tworzymy taką. Na początku tworzymy instancje z naszego "template", którego stworzyliśmy powyżej. Kolejne 4 linijki to: tworzenie świata, przypisanie dynamicznego id instancji temu światu, przypisanie id instancji, oraz dodanie świata do listy instancji. Następnie podajemy informacje do konsoli o stworzeniu instancji. Na końcu gracz zostaje dodany do listy obiektów które mogą przebywać w instancji i przeniesiony do środka używając metody która wcześniej stworzyliśmy.

Całość skryptu w tym momencie:

/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package instances.WlasnaInstancja;

import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager.InstanceWorld;
import com.l2jserver.gameserver.model.entity.Instance;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.quest.Quest;
/**
 * @author InsOmnia
 */

public class WlasnaInstancja extends Quest
{
private static final int[] enterCords = { 1, 2, 3 };
private static final int INSTANCE_ID = 134;
public WlasnaInstancja(int questId, String name, String descr)
{
super(questId, name, descr);
}

private synchronized void enterInstance(L2PcInstance player)
{
//sprawdzamy czy gracz jest już w jakiejś instancji
InstanceWorld world = InstanceManager.getInstance().getPlayerWorld(player);
if (world != null)
{
if (world.templateId != INSTANCE_ID)
{
player.sendPacket(new SystemMessage(SystemMessageId.ALREADY_ENTERED_ANOTHER_INSTANCE_CANT_ENTER));
return;
}
Instance inst = InstanceManager.getInstance().getInstance(world.instanceId);
if (inst != null)
teleportPlayer(player, enterCords, world.instanceId);
return;
}
//New instance
else
{
final int instanceId = InstanceManager.getInstance().createDynamicInstance("SealOfTheEmperor.xml");
world = InstanceManager.getInstance().new InstanceWorld();
world.instanceId = instanceId;
world.templateId = INSTANCE_ID;
InstanceManager.getInstance().addWorld(world);
_log.info("SealOfTheEmperor: started instance: " +instanceId + " created by player: " + player.getName());
world.allowed.add(player.getObjectId());
teleportPlayer(player, enterCords, instanceId);
}
}

private static final void teleportPlayer(L2PcInstance player, int[] coords, int instanceId)
{
player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
        player.setInstanceId(instanceId);
player.teleToLocation(coords[0], coords[1], coords[2], false);
}

public static void main(String[] args)
{
new WlasnaInstancja(196, "WlasnaInstancja", "custom");
}
}


Jutro dodam kolejny podpunkt poradnika, mianowicie, jak stworzyć npc który nas będzie teleportować do środka, jakie są sposoby dodawania npc wewnątrz instancji, jak bezpiecznie teleportować gracza wewnątrz instancji (metoda teleportPlayer nie wystarcza)


Jeśli macie jakieś problemy, coś jest niejasne, pytajcie.


Naito -- Autor postu otrzymał pochwałę !
« Ostatnia zmiana: Wrzesień 04, 2010, 04:27:29 pm wysłana przez Naito »
I would love to change the world, but they won't give me the source code.
My software never has bugs. It just develops random features.
Let's Kick Python Out of L2J.



  • Wiadomości: 375

  • Pochwał: -2

Odp: [Poradnik] Tworzenie instancji.
« Odpowiedź #1 dnia: Wrzesień 04, 2010, 01:32:11 pm »
kolejny + się należy :)


  • Wiadomości: 161

  • Pochwał: 2

  • Lineage 2 Player <3
Odp: [Poradnik] Tworzenie instancji.
« Odpowiedź #2 dnia: Czerwiec 15, 2011, 01:42:53 pm »
Jutro dodam kolejny podpunkt poradnika, mianowicie, jak stworzyć npc który nas będzie teleportować do środka, jakie są sposoby dodawania npc wewnątrz instancji, jak bezpiecznie teleportować gracza wewnątrz instancji (metoda teleportPlayer nie wystarcza)
Mistrzu :D

Gdzie to jest bo szukam i lipa xD
Head admin z Rosji dlatego lt strona
admin to ja


  • Wiadomości: 466

  • Pochwał: 1

Odp: [Poradnik] Tworzenie instancji.
« Odpowiedź #3 dnia: Czerwiec 15, 2011, 01:47:37 pm »
Jutro dodam kolejny podpunkt poradnika, mianowicie, jak stworzyć npc który nas będzie teleportować do środka, jakie są sposoby dodawania npc wewnątrz instancji, jak bezpiecznie teleportować gracza wewnątrz instancji (metoda teleportPlayer nie wystarcza)
Mistrzu :D

Gdzie to jest bo szukam i lipa xD

Weź sobie wybraną instancję z gamserver (kamaloka, pailaka, fortress dungeon etc), przejrzyj i zmodyfikuj. Wcale nie są jakieś tam bajecznie trudne.



Finaly retired, L2 is not fun anymore.