Jump to content

Recommended Posts

Posted

Ο IronMan (aka) Tony Stark, δεν είχε πολύ μυαλό. Είχε πολύ καλά εργαλεία. Σε αυτό το topic θα σχεδιάσουμε μαζί μία μηχανή για Events.

 

Οι στόχοι του Topic:

 

1)Σχεδιασμός μηχανής για Event.

2)Καλή χρήση της Java.

3)Βήμα προς βήμα οδηγείες και για αυτούς που ξέρουν πολύ λίγη Java.

4)Σχεδιασμός ενός απλού Event.

 

Προαπαιτούμενα:

- Ο αναγνώστης γνωρίζει πώς να κάνει Compile με NetBeans ή Eclipse.

- O αναγνωστης γνωρίζει πώς να περνάει στο pack του Patches.

- O αvαγνωστης γνωρίζει τα πολύ βασικά για την Java.

- Χρησιμοποιούμε L2JServer epilogue ( αλλά και Interlude μας βολεύει. )

- Επισης μας βολευόυν τα δευτερέυοντα packs ( l2jbrazil, l2jteon, l2jarchid και λοιπές μαλακίες ).

 

Αν διαβάζεις αυτό το topic και δεν γνωρίζεις τα πρώτα τρία από παραπάνω φύγε από το topic, δεν θα καταλάβεις τίποτα. Απλά περίμενε να τελειώσουμε για να πάρεις το Patch έτοιμο στο τέλος (όπως άλλωστε συνηθίζεις εδώ και καιρό ...:) ). Δεν κάνω post την μηχανή για Events κατευθείαν παρόλο που την έχω έτοιμη γιατί στόχος του topic δεν είναι απλά να πετάξω ένα patch ξεκάρφωτο αλλά να δείξω πώς να γράφει κανείς σωστά κώδικα και να σχεδιάζει ( τουλάχιστον για τους 10 - 15 που ενδιαφέρονται ). Ξεκινάμε :).

 

Τα προβλήματα που έχουμε με τα Events αυτή τη στιγμή είναι οτι το καθένα ( tvt,dm,ctf ) πρέπει να το περάσεις σε 15 διαφορετικά μέρη του κώδικα. Επίσης με δεδομένο ένα event δεν είναι εύκολο να το τροποποιήσεις ώστε να φτιάξεις ένα event. Με βάση αυτές τις δύο παρατηρήσεις θα σχεδιάσουμε την μηχανή μας. Το πρώτο πράγμα που θα πρέπει να κάνουμε είναι να βρούμε τι κοινό έχουν τα περισσότερα events μεταξύ τους. Εγώ σκέυτηκα ώς εξής.

 

Κάθε event οτιδήποτε και να κάνει, περνάει από μία σειρά από στάδια. Για παράδειγμα:

 

-TVTEvent : Registration --> fighting --> rewarding --> end.

-CTFEvent: Registration --> fighting --> rewarding --> end.

 

Σαν πρώτη ιδέα λοιπον μπορούμε να πούμε οτι ένα event αποτελείτε από ένα σύνολο από στάδια. Με βάση αυτό ανακύπτει η ερώτηση: Πώς μεταβαίνουμε από στάδιο σε στάδιο ? Και η απάντηση θα μπορούσε να ήταν κάθε στάδιο εκτελεί κάποιες ενέργιες όταν ενεργοποιείτε, κάποιες ενέργειες όταν απενεργοποιείται και ενημερώνει το Event να μετακινηθεί στο επόμενo στάδιο. Ένα ολοκληρωμένο παράδειγμα είναι το TvTEvent όπως φαίνεται παρακάτω:

 

tvtevent.jpg

 

Αυτό που φαίνεται εξαρχής είναι οτι κάθε state κάνει κάποια πράγματα στην αρχή, κάποια στο τέλος και ενδιάμεσα ελέγχει συνθήκες. ΠΧ αν τελείωσε ο χρόνος του, άν δεν ικανοποιούνται οι συνθήκες και ενημερώνει το event λέγοντάς του σε ποιό state να μεταβεί. Για παράδειγμα άν το Registration State δεί οτι δέν υπάρχουν αρκετά άτομα για να γίνει το Event ενημερώνει το Event να λήξει. Αλλιώς του λέει να μεταβέι στο Fighting State.

 

To Be Continued.

Posted

Κάθε event έχει μιά κατάσταση λειτουργίας και μιά κατάσταση Register. Για παράδειγμα ένα event είναι ενεργό ή ανενεργό. Επίσης ένα event έχει ενεργοποιημένη την εγγραφή ή απενεργοποιημένη ή δεν έχει καθόλου εγγραφή. Οι παρακάτω κώδικες αποτελόυν τμήμα του κάθε event και είναι Enumerations.

 

package L2Relapse.EventEngine.utils;

/**
* @author Issle
* 
* An event should be active or inactive. 
* All inner states of the event should not
* be in an enumeration, cuase the form a unique
* state class in the state machine model.
*
*/
public enum EventStatus
{
active, inactive
}

 

 

καί

 

package L2Relapse.EventEngine.utils;

/**
* @author Issle
*
*/
public enum RegistrationStatus
{
free,open,closed
}

 

Αυτά τα δύο ορίζουν πλήρως την κατάσταση ενός Event εξωτερικά, όπως την βλέπει ένας χρήστης που δεν συμετέχει στο Event.

Posted

Ας πάμε τώρα στο Event State.

 

Κάθε Event State, έχει τα παρακάτω:

 

1)Έναν αριθμό που προσδιορίζει την θέση του ανάμεσα στα υπόλοιπα state του event.

2)Έναν αριθμό που προσδιορίζει ποιό state θα ακολουθήσει μετά την λήξη του.

3)Έναν αριθμό που προσδιορίζει για πόσο χρόνο θα διαρκέσει ένα State.

4)Αναφορά στο Event στο οποίο ανήκει, ας το ονομάσουμε AbstractEvent.

 

1)Μία συνάρτηση εισόδου (onEnterState()) που λέει τι θα γίνει μόλις το State ενεργοποιηθεί.

2)Μία συνάρτηση εξόδου ( onExitState()) που λέει τι θα γίνει μόλις το State τελειώσει.

3)Μία συνάρτηση ελέγχουν (checkConditions()) που εκτελείτε κάθε X seconds και ελέγχει την κατάσταση.

 

package L2Relapse.EventEngine;


/**
* @author Issle
*
*/
public abstract class AbstractEventState
{
protected int stateId;
protected int nextStateId;
protected int duration = 240000;
protected int remainingTime;
protected AbstractEvent activeEvent;

public void initializeTime()
{
	remainingTime = duration;
}

public AbstractEvent getEvent()
{
	return activeEvent;
}

public int getNextStateId()
{
	return nextStateId;
}

public void decreaseTime()
{
	remainingTime -= activeEvent.getClockRate();
}
public abstract void onEnterState();

public abstract void onExitState();

public abstract boolean checkConditions();
}

 

Η κλάση αυτή είναι Abstract που σημένει οτι μέρη της κλάσης δεν υλοποιούνται και ούτε μπορεί να χρησημοποιηθεί. Η κλάση αυτή ορίζει ένα πρότυπο για το πώς θα σχεδιαστούν τα States. Δηλαδή ορίζει για παράδειγμα οτι όλα τα States έχουν συνάρτηση onEnterState() αλλά καθένα ίσως την υλοποιήσει διαφορετικά.

Posted

Όμοια και για το Event έχουμε ένα AbstractEvent που ορίζει το καλούπι για όλα τα Events.

Κάθε event έχει:

 

1)Ρολόι

2)Όνομα

3)Λίστα από στάδια ( px Registration , Fight ktl ktl ).

 

Επίσης το Event περιέχει συνθήκες ελέγχου onKill κτλ. Δεν υλοποιούνται γιατί όπως και προηγουμένος η κλάση αποτελεί καλούπι κατα κάποιο τρόπο. Επίσης έχει έναν χρονιστή ( που θέλει λίγη βελτίωση και Optimization  :-\ sorry ).

package L2Relapse.EventEngine;

import java.util.LinkedList;

import com.l2jserver.gameserver.ThreadPoolManager;
import L2Relapse.EventEngine.utils.EventStatus;
import L2Relapse.EventEngine.utils.RegistrationStatus;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;

/**
* @author Issle
* 
* Common information that all the events use.
*
*/
public abstract class AbstractEvent
{
public LinkedList<AbstractEventState> eventStates = new LinkedList<AbstractEventState>();

//Setting event parameters.
public int clockRate = 10000;
public String name = "NoName";

//The active state of this event.
public AbstractEventState activeState;

//The status of the event ( open /closed ).
public EventStatus eventStatus;

public RegistrationStatus registrationStatus;

/**
 * This is the core initialization of the event engine. It
 * reads the first state, and then schedules the checks for
 * the advancement of the event. The clock rate will not 
 * affect the slow/fast pace of the event. It controls the
 * rate in which the core checks for conditions in each event
 * state.
 */
public void startEvent()
{
	if(eventStates.isEmpty())
		return;

	//The event has started, change its status to active.
	eventStatus = EventStatus.active;

	//Get the activeState of the event whici is always the first state.
	activeState = eventStates.get(0);

	//Execute the activeState.
	activeState.onEnterState();

	//Check the advancing conditions on the future.
	ThreadPoolManager.getInstance().scheduleGeneral(new ConditionTask(this), clockRate);
}

/**
 * This class checks the active states conditions. If
 * the conditions are met, the state advances. Each state
 * indicates to what state the system must advance.
 * 
 * @author Issle
 *
 */
public class ConditionTask implements Runnable
{
	AbstractEvent event;

	public ConditionTask(AbstractEvent event)
	{
		this.event = event;
	}
	public void run()
	{
		//Are the conditions met ?
		if(activeState.checkConditions())
		{
			//Exits the current state.
			activeState.onExitState();

			//Tries to load the next state.
			if(activeState.getNextStateId()!= 0)
			{
				//Change the active state.
				activeState = eventStates.get(activeState.getNextStateId()-1);

				//Enter the current state.
				activeState.onEnterState();
			}
		}

		//If there is NO other state, then the event has ended.
		//In that case do not schedule a new conditions task.
		if(activeState.getNextStateId()!= 0)
		{
			ThreadPoolManager.getInstance().scheduleGeneral(new ConditionTask(event), clockRate);
			return;
		}

		//else ...
		TSManager.clearEvent();
		System.out.println("Event is now inactive.");
	}

}

public String getName()
{
	return name;
}

public void setEventStatus(EventStatus evt)
{
	eventStatus = evt;
}

/**
 * @param activeChar
 */
public abstract void register(L2PcInstance activeChar);

/**
 * @param activeChar
 */
public abstract void onEscapeUse(L2PcInstance activeChar);

/**
 * @param killerCharacter
 * @param killedPlayerInstance
 */
public abstract void onKill(L2Character killerCharacter, L2PcInstance killedPlayerInstance);

/**
 * @param playerInstance
 */
public abstract void onLogin(L2PcInstance playerInstance);

/**
 * @param playerInstance
 */
public abstract void onLogout(L2PcInstance playerInstance);

/**
 * Cleans the teams.
 */
public abstract void cleanTeams();

public void setRegistrationStatus(RegistrationStatus status) {
	registrationStatus = status;
}

/**
 * Returns the current events clock rate in milliseconds.
 * @return clockRate
 */
public int getClockRate() {
	return clockRate;
}
}

 

Πλέον έχουμε έτοιμο το καλούπι για τα state για τα Event και απομένεί να χρησιμοποιήσουμε μία κλάση που θα συνδέσει τα Event μας με το L2J.

 

To be continued ...

Posted

Για να συνδέσουμε όλα τα Events με το l2j θα χρησιμοποιήσουμε μια κλαση διεπαφής με όνομα TSManager.

 

package L2Relapse.EventEngine;

import java.util.Calendar;
import java.util.logging.Logger;
import javolution.util.FastMap;
import L2Relapse.EventEngine.Conquest.ConquestEvent;
import L2Relapse.EventEngine.utils.EventStatus;
import L2Relapse.Utils.Developer;

import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;

/**
* @author Issle
*
*/
public class TSManager
{
protected static final Logger _log = Logger.getLogger(TSManager.class.getName());

//Indicates if the TSManager is running an event atm.
public static boolean eventIsRunning = false;

//Holds the active event that is running atm.
public static AbstractEvent activeEvent = null;

//A list of the events that the manager will run and their dates.
public FastMap<Calendar, AbstractEvent> events;

//Sample event for testing.
ConquestEvent sampleEvent = new ConquestEvent(5000, "Conquest Event");


public void loadEvents()
{
	//Initialize the events list.
	events = new FastMap<Calendar, AbstractEvent>();
	activeEvent = sampleEvent;
}

public synchronized static void setEvent()
{
	activeEvent.setEventStatus(EventStatus.active);
	eventIsRunning = true;
}

/**
 * Inactivates the active event and informs the Scheduling manager.
 */
public synchronized static void clearEvent()
{
	activeEvent.setEventStatus(EventStatus.inactive);
	eventIsRunning = false;
}

public synchronized static boolean getEvent()
{
	return eventIsRunning;
}

public class ManagerTask implements Runnable
{
	public ManagerTask()
	{
		//doNothing.
	}

	@Override
	public void run()
	{
		ThreadPoolManager.getInstance().scheduleGeneral(new ManagerTask(), 15000);

		if(getEvent())
		{
			Developer.printEventMessage("THere is an event running.");
			return;
		}

		setEvent();
		activeEvent.startEvent();
	}
}

public static void onLogin(L2PcInstance activeChar)
{
	if(eventIsRunning)
		activeEvent.onLogin(activeChar);
}
public static void onLogout(L2PcInstance activeChar)
{
	if(eventIsRunning)
		activeEvent.onLogout(activeChar);
}
public static void onKill(L2Character killerCharacter, L2PcInstance killedPlayerInstance)
{
	if(eventIsRunning)
		activeEvent.onKill(killerCharacter, killedPlayerInstance);
}
public static void onEscapeUse(L2PcInstance activeChar)
{
	if(eventIsRunning)
		activeEvent.onEscapeUse(activeChar);
}

public static boolean isInEvent(L2PcInstance activeChar)
{
	if(eventIsRunning && activeEvent != null)
	{
		return true;
	}
	return false;
}

private TSManager()
{
	_log.info("[L2Relapse]Starting Time Scheduling Manager.");
	loadEvents();
	ThreadPoolManager.getInstance().scheduleGeneral(new ManagerTask(), 15000);
}

public static class SingletonHolder{
	public static final TSManager INSTANCE = new TSManager();
}

public static TSManager getInstance(){
	return SingletonHolder.INSTANCE;
}
}

Posted

Στο επόμενο post τώρα που η μηχανή είναι έτοιμη θα σχεδιάσουμε ένα Event στο οποίο οι πέκτες κάνουν PVP για ένα Raid Boss.

Posted

Poli kalo file ama to testarei kaneis kai odos work tha pareis +1 karma

Tzampa tha paei to karma ;) Tha to ksanaxaso brizontas tous axristous mods kai devs. H mhxanh mexri tora einai etoimi alla den exei events pano opos den mporeis na testareis tipota :) Otan kano post to proto event tote tha mporeis na testareis eykola.

  • 4 weeks later...
  • 3 months later...
Posted

Polu kalo tha to dokimaso aurio :) keep sharing.

lei den ine gia dokimi akomh otan ine tha to bali ara den mporis na testaris. pantos ksero elaxista pramata apo java exo gracia final l2jfree opote den me help emena pantos brabo sou

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Posts

    • Hello, our prices are either average or often even lower than the market. At some point, it happens that adena is very expensive, but it is worth waiting and it falls in price. In the first days, adena usually costs a lot of money because of the level race.
    • hello, do you have maybe source nwindow.u for protocol 24?
    • Now begins your final fall, you don't know who you messed with and who I am, nor can you imagine what awaits you. Dragon Network will have to answer for its actions before the FBI, and thus begins its downfall.
    • This post originally appeared on zupyak. The EA FC 26 Closed Beta is almost here, giving select players an exclusive first look at the game before its official release. Running from August 6 to August 26, 2025, this beta will let testers try out key gameplay changes and provide feedback to EA. If you're eager to secure a beta code, this guide will walk you through everything you need to know—from eligibility requirements to how to maximize your chances of getting an invite.   How to Get an EA FC 26 Beta Code 1. Beta Codes Are Account-Locked (No Sharing!) • If you receive a beta code, it will be tied to your EA account and cannot be shared or sold. • Attempting to share or buy a code is against EA's NDA (Non-Disclosure Agreement) and will result in a ban. 2. Check Your EA Account Settings • Log in to the EA website and go to Account Settings. • Navigate to Communication Preferences and ensure you're opted in for: • All EA Sports games, including FC 25 and FC 24 • The platform you actually play on • Promotional emails 3. Sign Up for EA Playtesting • Visit the EA Playtesting portal and register. This increases your chances of being selected for beta access. 4. Play FC 25 Regularly EA prioritizes active players, especially those who compete in Division Rivals and FUT Champions. The more you play, the higher your chances of receiving an invite. 5. Check Your Email (Including Spam!) If you don't receive one immediately, check again on August 13, as EA sometimes sends codes in waves.   What Game Modes Are Available in the Beta? • Kickoff (available to all testers) • Ultimate Team (FUT) • Clubs • Career Mode Your access to modes beyond Kickoff depends on your past gameplay history in FC 25.   Important Beta Rules & Restrictions Do: • Test the game and provide feedback in the official EA beta forums. • Keep all beta details confidential—no streaming, screenshots, or social media posts. Don't: • Share or sell your beta code (it won't work for anyone else). • Discuss the beta publicly—breaking the NDA can lead to account bans. • Expect progress to carry over—the beta is for testing only.   Final Tips to Improve Your Chances • Play FC 25 frequently—active players get priority. • Only select platforms you own—only available for consoles. • Check your spam folder—beta emails sometimes land there. • Avoid VPNs—EA may restrict access based on region (US & UK have higher priority).   What If You Don't Get a Beta Code? The beta code has been released on Augest 4. If you didn't receive one, don't worry, as EA sometimes sends codes in waves. Final Thoughts The EA FC 26 Closed Beta is a fantastic opportunity for dedicated fans to shape the future of the game while enjoying early access. By following these steps and staying active in FC 25, you can maximize your chances of securing a coveted beta code. Remember, confidentiality is key—so keep all details private and abide by EA's rules. And when the full game officially launches, consider buying FC 26 coins to give yourself an edge in building your Ultimate Team and dominating the competition! Are you ready for EA FC 26? Let us know your thoughts in the comments below!
  • Topics

×
×
  • Create New...

AdBlock Extension Detected!

Our website is made possible by displaying online advertisements to our members.

Please disable AdBlock browser extension first, to be able to use our community.

I've Disabled AdBlock