Jump to content
  • 0

Respawn After...(Threadpoolmanager)


Question

Posted (edited)

Hello guys,
I have a custom zone and whenever you die in that zone it shows you the timer when you will respawn and after timer reaches 0 it respawns you.This was my first try:
 

	public void onDieInside(L2Character character)
	{
		
		if(character instanceof L2PcInstance){
			final L2PcInstance player = (L2PcInstance) character;
			countdown = 5;
			ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Runnable(){
				@Override
				public void run(){
						if(player.isDead()){
							if(countdown >0){
							SystemMessage smg = SystemMessage.getSystemMessage(SystemMessageId.RESPAWN_AFTER_S1_SECONDS);
							smg.addString(String.valueOf(countdown));
							player.sendPacket(SystemMessageId.RESPAWN_AFTER_S1_SECONDS);
							countdown--;
							}else if(countdown == 0){
				                player.doRevive();
				    			int x =	174132 + (int)(Math.random() * ((179862 - 174132) + 1));
				    			int y = 112225 + (int)(Math.random() * ((117715 - 112225) + 1));
				    			int z = -7708;
				    			Location loc = new Location(x, y, z);
				                player.teleToLocation(loc,0);
							}
						}
				}
				
			}
			,0,1000);
			
		}
		
	}

It works fine for first time,but then it just get shorter and shorter.I believe it's because thread doesn't stop working after respawning player,so whenever a player dies again the countdown is set to 5,but there is 2threads running and subtracting 1from countdown and then threads just keep increasing.
My second try was this method:

	public void onDieInside(L2Character character)
	{
		
		if(character instanceof L2PcInstance){
			final L2PcInstance player = (L2PcInstance) character;
			countdown = 5;
			while(countdown > 0 && player.isDead()){
				ThreadPoolManager.getInstance().scheduleGeneral(new showCountdown(countdown,player), 6000-countdown*1000);
				countdown--;
			}
			ThreadPoolManager.getInstance().scheduleGeneral(new Runnable(){
				@Override
				public void run(){
					if(player.isDead()){
	                player.doRevive();
	    			int x =	174132 + (int)(Math.random() * ((179862 - 174132) + 1));
	    			int y = 112225 + (int)(Math.random() * ((117715 - 112225) + 1));
	    			int z = -7708;
	    			Location loc = new Location(x, y, z);
	                player.teleToLocation(loc,0);
					}
				}
			}, 6000);
			
		
			
		}
		
	}

This is showCountdown class:

	class showCountdown implements Runnable{
		int timer = 0;
		L2PcInstance player;
		public showCountdown(int countdown,L2PcInstance p){
			timer = countdown;
			player = p;
		}
		@Override
		public void run(){
			SystemMessage smg = SystemMessage.getSystemMessage(SystemMessageId.RESPAWN_AFTER_S1_SECONDS);
			smg.addNumber(timer);
			player.sendPacket(smg);
		}
	}

It works just fine,but it seems dumb just to create so many Threads for a simple countdown.

Edited by StealthyS4m

15 answers to this question

Recommended Posts

  • 0
Posted

The second code is about fine, you could have done it with one thread but thats nothing for the resources.

 

Never use that shutdown, it will destroy your thread manager.

You can cancel thread by first saving it as ScheduledFuture<?>, for example:

ScheduledFuture<?> thread = ThreadPoolManager.getInstance().schedule(new Something(), 5000L);
thread.cancel(false);

However, in the first program it would be hard to use that method(you would need to get ScheduledFuture<?> thread from inside somehow)

  • 0
Posted

If you can read the whole post,I've got 2ways to do my thing and one of them is working,just I am not sure if it's the best way.
I may have been a bit unclear in my first post.But countdown--; is the number that will be written on sysmsg.
For example,at first countdown is 5,after second the thread runs again and this time countdown is 4,so it will say "You will respawn after 4 seconds",then "You will respawn after 3seconds" and so on.The reason it gets shorter is because when you die second time my method creates another thread,so now there is two threads,which are subtracting countdown.The more you die,the less respawn time is.
To fix it I need to know how to destroy ThreadPoolManager after it runs everything it needs:
 

				public void run(){
						if(player.isDead()){
							if(countdown >0){
							SystemMessage smg = SystemMessage.getSystemMessage(SystemMessageId.RESPAWN_AFTER_S1_SECONDS);
							smg.addString(String.valueOf(countdown));
							player.sendPacket(SystemMessageId.RESPAWN_AFTER_S1_SECONDS);
							countdown--;
							}else if(countdown == 0){
				                player.doRevive();
				    			int x =	174132 + (int)(Math.random() * ((179862 - 174132) + 1));
				    			int y = 112225 + (int)(Math.random() * ((117715 - 112225) + 1));
				    			int z = -7708;
				    			Location loc = new Location(x, y, z);
				                player.teleToLocation(loc,0);
							}else{ 
                                                      DestroyThisThreadSomehow();
}
						}
				}



P.S. I believe I have problems expressing my problems associated with programming in English language,cause I am not very good in both of them. ^_^

  • 0
Posted

You can use my code that i have wrote for starting new Event:

	private static class StartEventThread implements Runnable
	{
		private static final int[] STOP_TIMES = {1800, 900, 600, 300, 60, 30, 15, 10, 5, 0};//In which seconds Thread have to stop to show the message
		private final AbstractFightClub duplicatedEvent;//This is for starting event, you don't need it
		private final int secondsToStartEvent;

		private StartEventThread(AbstractFightClub duplicatedEvent, int secondsToStartEvent)
		{
			this.duplicatedEvent = duplicatedEvent;
			this.secondsToStartEvent = secondsToStartEvent;
		}

		@Override
		public void run()
		{
			try
			{
				if(getInstance().isNextEventBlocked())
					return;

				int timeToShow = -1;//Time in Seconds to show in the message
				int timeToWait = -1;//Seconds to wait until next STOP_TIME
                                //This is a bit advanced, the reason is if i would start StartEventThread to finish after 1900 seconds, it would first wait 100 seconds, print the message and then go on normally
				for(int i = 0;i < STOP_TIMES.length;i++)
				{
					if (secondsToStartEvent >= STOP_TIMES[i])
					{
						if (secondsToStartEvent == STOP_TIMES[i])
						{
							timeToShow = STOP_TIMES[i];
							if(i == STOP_TIMES.length - 1)
								timeToWait = 0;
							else
								timeToWait = STOP_TIMES[i] - STOP_TIMES[i + 1];
						}
						else
						{
							timeToWait = secondsToStartEvent - STOP_TIMES[i];
						}
						break;
					}
				}

				if(timeToShow >= 0)//Also timeToShow is only above 0, if left seconds until event == one of the STOP_TIMES. So in the example with 1900 seconds, message wouldnt show
				{
					if(timeToShow > 60)
						sendMsg(duplicatedEvent.getName() + " will start in " + (timeToShow / 60) + " minutes!");
					else if(timeToShow == 60)
						sendMsg(duplicatedEvent.getName() + " will start in 1 minute!");
					else if(timeToShow > 0)
						sendMsg(duplicatedEvent.getName() + " will start in " + timeToShow + " seconds!");
					else if(timeToShow == 0)
						sendMsg(duplicatedEvent.getName() + " Started!");
				}

				if(timeToWait > 0)
				{
					ThreadPoolManager.getInstance().schedule(new StartEventThread(duplicatedEvent, secondsToStartEvent - timeToWait), (long) timeToWait * 1000L);
				}
				else
				{
					getInstance().startCurrentEvent();
				}
			}
			catch (RuntimeException e)
			{
				LOG.error("Error while launching Event ", e);
			}
		}
	}
}
  • 0
Posted

About the problem of shorter waiting if you die once again. There are 2 ways:

1. When the thread stops to send the message, you can check if player is still dead, if not then cancel the thread

2. You can save thread somewhere and when player have been resurrected you can cancel the thread

  • 0
Posted (edited)

You mean something like this:
 

ThreadPoolManager tpm = ThreadPoolManager.getInstance();
if(condition_means_shutdown)
tpm.shutdown();

Is my method,the one who works(second one) fine?Or does it use too many resources for such an easy task?

Edited by StealthyS4m
  • 0
Posted (edited)
ScheduledFuture<?> thread = ThreadPoolManager.getInstance().schedule(new Something(), 5000L);
class Something implements Runnable{
    public void run(){
if(conditionMeansCancel){
cancel(thread);
}
}
}
public void cancel(ScheduledFuture<?> thread){
thread.cancel();
}

Wouldn't it make it work?I believe only in C++ it creates new copy when passing variable to argument.

Edited by StealthyS4m
  • 0
Posted

You could make something like that:

private ScheduledFuture<?> thread;

public void startThread()
{
	thread = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Something(), 5000L, 5000L);
}

private static class Something implements Runnable
{
	@Override
	public void run()
	{
		getInstance().stopThread();
	}
}

private void stopThread()
{
	thread.cancel(false);
}

private static class SingletonHolder
{
	private static final MainClass instance = new MainClass();
}

public static MainClass getInstance()
{
	return SingletonHolder.instance;
}

But it's a lot better to use schedule(and if you want to cancel it, just put if(shouldThreadBeCancelled()) return;) than scheduleGeneralAtFixedRate and cancelling it that kind of way.

  • 0
Posted


+

+ @Override

+ public void onDieInside(final L2Character character)

+ {

+ if (character instanceof L2PcInstance)

+ {

+ final L2PcInstance activeChar = ((L2PcInstance) character);

+ if(revive)

+ {

+ ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()

+ {

+ @Override

+ public void run()

+ {

+ activeChar.doRevive();

+ heal(activeChar);

+ int[] loc = spawn_loc[Rnd.get(spawn_loc.length)];

+ activeChar.teleToLocation(loc[0]+Rnd.get(-radius,radius), loc[1]+Rnd.get(-radius,radius), loc[2]);

+ }

+ },revive_delay*1000);

+ }

+ }

+ }

+

Vampir thread really doesnt stops also here?

  • 0
Posted

It does, but we are talking about first example(with scheduleGeneralAtFixedRate(Runnable, long, long) method)

  • 0
Posted

Yes, but your code isn't complete.

The goal:

-6 Seconds: Send "Respawn in 6 Seconds" message
-5 Seconds: Send "Respawn in 5 Seconds" message
-4 Seconds: Send "Respawn in 4 Seconds" message
-3 Seconds: Send "Respawn in 3 Seconds" message
-2 Seconds: Send "Respawn in 2 Seconds" message
-1 Seconds: Send "Respawn in 1 Second" message
0 Second: Respawn Player

The First code is bad because of scheduleGeneralAtFixedRate. This method is good if you want to make same repeated task every x amount of time, cancel it in rare cases. It's hard to cancel the method and to get "countdown" variable from inside the method.

The Second Code is quite fine, but it would be better with just 1 Thread.

Your code doesn't print any messages

  • 0
Posted (edited)

You got the choice to make 5 tasks firing one event, or one task firing 5 different events.

 

I had to code a similar thing for MDT rework on aCis. It looks like vampir code.

protected MonsterRace()
{
	...
            ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Announcement(), 0, 1000);
    }

	private class Announcement implements Runnable
	{
		public Announcement()
		{
		}
		
		@Override
		public void run()
		{
			if (_finalCountdown > 1200)
				_finalCountdown = 0;
			
			switch (_finalCountdown)
			{
				case 0:
					newRace();
					newSpeeds();
					
					_state = RaceState.ACCEPTING_BETS;
					_packet = new MonRaceInfo(_codes[0][0], _codes[0][1], getMonsters(), getSpeeds());
					
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, _packet, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber));
					break;
				
				case 30: // 30 sec
				case 60: // 1 min
				case 90: // 1 min 30 sec
				case 120: // 2 min
				case 150: // 2 min 30
				case 180: // 3 min
				case 210: // 3 min 30
				case 240: // 4 min
				case 270: // 4 min 30 sec
				case 330: // 5 min 30 sec
				case 360: // 6 min
				case 390: // 6 min 30 sec
				case 420: // 7 min
				case 450: // 7 min 30
				case 480: // 8 min
				case 510: // 8 min 30
				case 540: // 9 min
				case 570: // 9 min 30 sec
				case 630: // 10 min 30 sec
				case 660: // 11 min
				case 690: // 11 min 30 sec
				case 720: // 12 min
				case 750: // 12 min 30
				case 780: // 13 min
				case 810: // 13 min 30
				case 870: // 14 min 30 sec
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber));
					break;
				
				case 300: // 5 min
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(10));
					break;
				
				case 600: // 10 min
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(5));
					break;
				
				case 840: // 14 min
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(1));
					break;
				
				case 900: // 15 min
					_state = RaceState.WAITING;
					
					calculateOdds();
					
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_TICKET_SALES_CLOSED));
					break;
				
				case 960: // 16 min
				case 1020: // 17 min
					final int minutes = (_finalCountdown == 960) ? 2 : 1;
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S2_BEGINS_IN_S1_MINUTES).addNumber(minutes));
					break;
				
				case 1050: // 17 min 30 sec
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_BEGINS_IN_30_SECONDS));
					break;
				
				case 1070: // 17 min 50 sec
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_COUNTDOWN_IN_FIVE_SECONDS));
					break;
				
				case 1075: // 17 min 55 sec
				case 1076: // 17 min 56 sec
				case 1077: // 17 min 57 sec
				case 1078: // 17 min 58 sec
				case 1079: // 17 min 59 sec
					final int seconds = 1080 - _finalCountdown;
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS).addNumber(seconds));
					break;
				
				case 1080: // 18 min
					_state = RaceState.STARTING_RACE;
					_packet = new MonRaceInfo(_codes[1][0], _codes[1][1], getMonsters(), getSpeeds());
					
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_RACE_START), _sound1, _sound2, _packet);
					break;
				
				case 1085: // 18 min 5 sec
					_packet = new MonRaceInfo(_codes[2][0], _codes[2][1], getMonsters(), getSpeeds());
					
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, _packet);
					break;
				
				case 1115: // 18 min 35 sec
					_state = RaceState.RACE_END;
					
					// Populate history info with data, stores it in database.
					final HistoryInfo info = _history.get(_history.size() - 1);
					info.setFirst(getFirstPlace());
					info.setSecond(getSecondPlace());
					info.setOddRate(_odds.get(getFirstPlace() - 1));
					
					saveHistory(info);
					clearBets();
					
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_FIRST_PLACE_S1_SECOND_S2).addNumber(getFirstPlace()).addNumber(getSecondPlace()), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_RACE_END).addNumber(_raceNumber));
					_raceNumber++;
					break;
				
				case 1140: // 19 min
					Broadcast.toAllPlayersInZoneType(L2DerbyTrackZone.class, new DeleteObject(getMonsters()[0]), new DeleteObject(getMonsters()[1]), new DeleteObject(getMonsters()[2]), new DeleteObject(getMonsters()[3]), new DeleteObject(getMonsters()[4]), new DeleteObject(getMonsters()[5]), new DeleteObject(getMonsters()[6]), new DeleteObject(getMonsters()[7]));
					break;
			}
			_finalCountdown += 1;
		}
	}

It's a 20 minutes cycle event, you obviously have to recode, like inverting the timer to reuse the current timer as variable, add a stopping stuff, etc.

Edited by Tryskell
Guest
This topic is now closed to further replies.
×
×
  • Create New...