Merged with released L2J-Unity files.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.events.AbstractScript;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractEvent<T extends AbstractEventMember<?>>extends AbstractScript
|
||||
{
|
||||
private final Map<Integer, T> _members = new ConcurrentHashMap<>();
|
||||
private IEventState _state;
|
||||
|
||||
public final Map<Integer, T> getMembers()
|
||||
{
|
||||
return _members;
|
||||
}
|
||||
|
||||
public final T getMember(int objectId)
|
||||
{
|
||||
return _members.get(objectId);
|
||||
}
|
||||
|
||||
public final void addMember(T member)
|
||||
{
|
||||
_members.put(member.getObjectId(), member);
|
||||
}
|
||||
|
||||
public final void broadcastPacket(IClientOutgoingPacket... packets)
|
||||
{
|
||||
_members.values().forEach(member -> member.sendPacket(packets));
|
||||
}
|
||||
|
||||
public final IEventState getState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
public final void setState(IEventState state)
|
||||
{
|
||||
_state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getScriptName()
|
||||
{
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path getScriptPath()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* @return {@code true} if player is on event, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isOnEvent(L2PcInstance player)
|
||||
{
|
||||
return _members.containsKey(player.getObjectId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* @return {@code true} if player is blocked from leaving the game, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isBlockingExit(L2PcInstance player)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* @return {@code true} if player is blocked from receiving death penalty upon death, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isBlockingDeathPenalty(L2PcInstance player)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* @return {@code true} if player can revive after death, {@code false} otherwise.
|
||||
*/
|
||||
public boolean canRevive(L2PcInstance player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.eventengine.drop.IEventDrop;
|
||||
import com.l2jmobius.gameserver.model.events.AbstractScript;
|
||||
import com.l2jmobius.gameserver.model.events.EventType;
|
||||
import com.l2jmobius.gameserver.model.events.ListenerRegisterType;
|
||||
import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
|
||||
import com.l2jmobius.gameserver.model.events.annotations.RegisterType;
|
||||
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractEventManager<T extends AbstractEvent<?>>extends AbstractScript
|
||||
{
|
||||
private String _name;
|
||||
private volatile StatsSet _variables = StatsSet.EMPTY_STATSET;
|
||||
private volatile Set<EventScheduler> _schedulers = Collections.emptySet();
|
||||
private volatile Set<IConditionalEventScheduler> _conditionalSchedulers = Collections.emptySet();
|
||||
private volatile Map<String, IEventDrop> _rewards = Collections.emptyMap();
|
||||
|
||||
private final Set<T> _events = ConcurrentHashMap.newKeySet();
|
||||
private final Queue<L2PcInstance> _registeredPlayers = new ConcurrentLinkedDeque<>();
|
||||
private final AtomicReference<IEventState> _state = new AtomicReference<>();
|
||||
|
||||
public abstract void onInitialized();
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public StatsSet getVariables()
|
||||
{
|
||||
return _variables;
|
||||
}
|
||||
|
||||
public void setVariables(StatsSet variables)
|
||||
{
|
||||
_variables = new StatsSet(Collections.unmodifiableMap(variables.getSet()));
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public EventScheduler getScheduler(String name)
|
||||
{
|
||||
return _schedulers.stream().filter(scheduler -> scheduler.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public void setSchedulers(Set<EventScheduler> schedulers)
|
||||
{
|
||||
_schedulers = Collections.unmodifiableSet(schedulers);
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public Set<IConditionalEventScheduler> getConditionalSchedulers()
|
||||
{
|
||||
return _conditionalSchedulers;
|
||||
}
|
||||
|
||||
public void setConditionalSchedulers(Set<IConditionalEventScheduler> schedulers)
|
||||
{
|
||||
_conditionalSchedulers = Collections.unmodifiableSet(schedulers);
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public IEventDrop getRewards(String name)
|
||||
{
|
||||
return _rewards.get(name);
|
||||
}
|
||||
|
||||
public void setRewards(Map<String, IEventDrop> rewards)
|
||||
{
|
||||
_rewards = Collections.unmodifiableMap(rewards);
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public Set<T> getEvents()
|
||||
{
|
||||
return _events;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public void startScheduler()
|
||||
{
|
||||
_schedulers.forEach(EventScheduler::startScheduler);
|
||||
}
|
||||
|
||||
public void stopScheduler()
|
||||
{
|
||||
_schedulers.forEach(EventScheduler::stopScheduler);
|
||||
}
|
||||
|
||||
public void startConditionalSchedulers()
|
||||
{
|
||||
//@formatter:off
|
||||
_conditionalSchedulers.stream()
|
||||
.filter(IConditionalEventScheduler::test)
|
||||
.forEach(IConditionalEventScheduler::run);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public IEventState getState()
|
||||
{
|
||||
return _state.get();
|
||||
}
|
||||
|
||||
public void setState(IEventState newState)
|
||||
{
|
||||
final IEventState previousState = _state.get();
|
||||
_state.set(newState);
|
||||
onStateChange(previousState, newState);
|
||||
}
|
||||
|
||||
public boolean setState(IEventState previousState, IEventState newState)
|
||||
{
|
||||
if (_state.compareAndSet(previousState, newState))
|
||||
{
|
||||
onStateChange(previousState, newState);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
public final boolean registerPlayer(L2PcInstance player)
|
||||
{
|
||||
return canRegister(player, true) && _registeredPlayers.offer(player);
|
||||
}
|
||||
|
||||
public final boolean unregisterPlayer(L2PcInstance player)
|
||||
{
|
||||
return _registeredPlayers.remove(player);
|
||||
}
|
||||
|
||||
public final boolean isRegistered(L2PcInstance player)
|
||||
{
|
||||
return _registeredPlayers.contains(player);
|
||||
}
|
||||
|
||||
public boolean canRegister(L2PcInstance player, boolean sendMessage)
|
||||
{
|
||||
return !_registeredPlayers.contains(player);
|
||||
}
|
||||
|
||||
public final Queue<L2PcInstance> getRegisteredPlayers()
|
||||
{
|
||||
return _registeredPlayers;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
|
||||
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
|
||||
private void onPlayerLogout(OnPlayerLogout event)
|
||||
{
|
||||
final L2PcInstance player = event.getActiveChar();
|
||||
if (_registeredPlayers.remove(player))
|
||||
{
|
||||
onUnregisteredPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
/**
|
||||
* Triggered when a player is automatically removed from the event manager because he disconnected
|
||||
* @param player
|
||||
*/
|
||||
protected void onUnregisteredPlayer(L2PcInstance player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when state is changed
|
||||
* @param previousState
|
||||
* @param newState
|
||||
*/
|
||||
protected void onStateChange(IEventState previousState, IEventState newState)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
@Override
|
||||
public String getScriptName()
|
||||
{
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getScriptPath()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2World;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractEventMember<T extends AbstractEvent<?>>
|
||||
{
|
||||
private final int _objectId;
|
||||
private final T _event;
|
||||
private final AtomicInteger _score = new AtomicInteger();
|
||||
|
||||
public AbstractEventMember(L2PcInstance player, T event)
|
||||
{
|
||||
_objectId = player.getObjectId();
|
||||
_event = event;
|
||||
}
|
||||
|
||||
public final int getObjectId()
|
||||
{
|
||||
return _objectId;
|
||||
}
|
||||
|
||||
public L2PcInstance getPlayer()
|
||||
{
|
||||
return L2World.getInstance().getPlayer(_objectId);
|
||||
}
|
||||
|
||||
public void sendPacket(IClientOutgoingPacket... packets)
|
||||
{
|
||||
final L2PcInstance player = getPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
for (IClientOutgoingPacket packet : packets)
|
||||
{
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getClassId()
|
||||
{
|
||||
final L2PcInstance player = getPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
return player.getClassId().getId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setScore(int score)
|
||||
{
|
||||
_score.set(score);
|
||||
}
|
||||
|
||||
public int getScore()
|
||||
{
|
||||
return _score.get();
|
||||
}
|
||||
|
||||
public int incrementScore()
|
||||
{
|
||||
return _score.incrementAndGet();
|
||||
}
|
||||
|
||||
public int decrementScore()
|
||||
{
|
||||
return _score.decrementAndGet();
|
||||
}
|
||||
|
||||
public int addScore(int score)
|
||||
{
|
||||
return _score.addAndGet(score);
|
||||
}
|
||||
|
||||
public final T getEvent()
|
||||
{
|
||||
return _event;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class EventMethodNotification
|
||||
{
|
||||
private final AbstractEventManager<?> _manager;
|
||||
private final Method _method;
|
||||
private final Object[] _args;
|
||||
|
||||
/**
|
||||
* @param manager
|
||||
* @param methodName
|
||||
* @param args
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public EventMethodNotification(AbstractEventManager<?> manager, String methodName, List<Object> args) throws NoSuchMethodException
|
||||
{
|
||||
_manager = manager;
|
||||
_method = manager.getClass().getDeclaredMethod(methodName, args.stream().map(Object::getClass).toArray(Class[]::new));
|
||||
_args = args.toArray();
|
||||
}
|
||||
|
||||
public AbstractEventManager<?> getManager()
|
||||
{
|
||||
return _manager;
|
||||
}
|
||||
|
||||
public Method getMethod()
|
||||
{
|
||||
return _method;
|
||||
}
|
||||
|
||||
public void execute() throws Exception
|
||||
{
|
||||
if (Modifier.isStatic(_method.getModifiers()))
|
||||
{
|
||||
invoke(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to find getInstance() method
|
||||
for (Method method : _manager.getClass().getMethods())
|
||||
{
|
||||
if (Modifier.isStatic(method.getModifiers()) && (_manager.getClass().isAssignableFrom(method.getReturnType())) && (method.getParameterCount() == 0))
|
||||
{
|
||||
final Object instance = method.invoke(null);
|
||||
invoke(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void invoke(Object instance) throws Exception
|
||||
{
|
||||
final boolean wasAccessible = _method.isAccessible();
|
||||
if (!wasAccessible)
|
||||
{
|
||||
_method.setAccessible(true);
|
||||
}
|
||||
_method.invoke(instance, _args);
|
||||
_method.setAccessible(wasAccessible);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.commons.database.DatabaseFactory;
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.model.StatsSet;
|
||||
|
||||
import it.sauronsoftware.cron4j.PastPredictor;
|
||||
import it.sauronsoftware.cron4j.Predictor;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class EventScheduler
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(EventScheduler.class.getName());
|
||||
private final AbstractEventManager<?> _eventManager;
|
||||
private final String _name;
|
||||
private final String _pattern;
|
||||
private final boolean _repeat;
|
||||
private List<EventMethodNotification> _notifications;
|
||||
private ScheduledFuture<?> _task;
|
||||
|
||||
public EventScheduler(AbstractEventManager<?> manager, StatsSet set)
|
||||
{
|
||||
_eventManager = manager;
|
||||
_name = set.getString("name", "");
|
||||
_pattern = set.getString("minute", "*") + " " + set.getString("hour", "*") + " " + set.getString("dayOfMonth", "*") + " " + set.getString("month", "*") + " " + set.getString("dayOfWeek", "*");
|
||||
_repeat = set.getBoolean("repeat", false);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public long getNextSchedule()
|
||||
{
|
||||
final Predictor predictor = new Predictor(_pattern);
|
||||
return predictor.nextMatchingTime();
|
||||
}
|
||||
|
||||
public long getNextSchedule(long fromTime)
|
||||
{
|
||||
final Predictor predictor = new Predictor(_pattern, fromTime);
|
||||
return predictor.nextMatchingTime();
|
||||
}
|
||||
|
||||
public long getPrevSchedule()
|
||||
{
|
||||
final PastPredictor predictor = new PastPredictor(_pattern);
|
||||
return predictor.prevMatchingTime();
|
||||
}
|
||||
|
||||
public long getPrevSchedule(long fromTime)
|
||||
{
|
||||
final PastPredictor predictor = new PastPredictor(_pattern, fromTime);
|
||||
return predictor.prevMatchingTime();
|
||||
}
|
||||
|
||||
public boolean isRepeating()
|
||||
{
|
||||
return _repeat;
|
||||
}
|
||||
|
||||
public void addEventNotification(EventMethodNotification notification)
|
||||
{
|
||||
if (_notifications == null)
|
||||
{
|
||||
_notifications = new ArrayList<>();
|
||||
}
|
||||
_notifications.add(notification);
|
||||
}
|
||||
|
||||
public List<EventMethodNotification> getEventNotifications()
|
||||
{
|
||||
return _notifications;
|
||||
}
|
||||
|
||||
public void startScheduler()
|
||||
{
|
||||
if (_notifications == null)
|
||||
{
|
||||
LOGGER.info("Scheduler without notificator manager: " + _eventManager.getClass().getSimpleName() + " pattern: " + _pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
final Predictor predictor = new Predictor(_pattern);
|
||||
final long nextSchedule = predictor.nextMatchingTime();
|
||||
final long timeSchedule = nextSchedule - System.currentTimeMillis();
|
||||
if (timeSchedule <= (30 * 1000))
|
||||
{
|
||||
LOGGER.warning("Wrong reschedule for " + _eventManager.getClass().getSimpleName() + " end up run in " + (timeSchedule / 1000) + " seconds!");
|
||||
ThreadPoolManager.getInstance().scheduleEvent(this::startScheduler, timeSchedule + 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_task != null)
|
||||
{
|
||||
_task.cancel(false);
|
||||
}
|
||||
|
||||
_task = ThreadPoolManager.getInstance().scheduleEvent(() ->
|
||||
{
|
||||
run();
|
||||
updateLastRun();
|
||||
|
||||
if (isRepeating())
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleEvent(this::startScheduler, 1000);
|
||||
}
|
||||
}, timeSchedule);
|
||||
}
|
||||
|
||||
public boolean updateLastRun()
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO event_schedulers (eventName, schedulerName, lastRun) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE eventName = ?, schedulerName = ?, lastRun = ?"))
|
||||
{
|
||||
ps.setString(1, _eventManager.getName());
|
||||
ps.setString(2, _name);
|
||||
ps.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
|
||||
ps.setString(4, _eventManager.getName());
|
||||
ps.setString(5, _name);
|
||||
ps.setTimestamp(6, new Timestamp(System.currentTimeMillis()));
|
||||
ps.execute();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Failed to insert/update information for scheduled task manager: " + _eventManager.getClass().getSimpleName() + " scheduler: " + _name, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void stopScheduler()
|
||||
{
|
||||
if (_task != null)
|
||||
{
|
||||
_task.cancel(false);
|
||||
_task = null;
|
||||
}
|
||||
}
|
||||
|
||||
public long getRemainingTime(TimeUnit unit)
|
||||
{
|
||||
return (_task != null) && !_task.isDone() ? _task.getDelay(unit) : 0;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
for (EventMethodNotification notification : _notifications)
|
||||
{
|
||||
try
|
||||
{
|
||||
notification.execute();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning("Failed to notify to event manager: " + notification.getManager().getClass().getSimpleName() + " method: " + notification.getMethod().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public interface IConditionalEventScheduler
|
||||
{
|
||||
public boolean test();
|
||||
|
||||
public void run();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public interface IEventState
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ScheduleTarget
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.conditions;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager;
|
||||
import com.l2jmobius.gameserver.model.eventengine.EventScheduler;
|
||||
import com.l2jmobius.gameserver.model.eventengine.IConditionalEventScheduler;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class BetweenConditionalScheduler implements IConditionalEventScheduler
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(BetweenConditionalScheduler.class.getName());
|
||||
private final AbstractEventManager<?> _eventManager;
|
||||
private final String _name;
|
||||
private final String _scheduler1;
|
||||
private final String _scheduler2;
|
||||
|
||||
public BetweenConditionalScheduler(AbstractEventManager<?> eventManager, String name, String scheduler1, String scheduler2)
|
||||
{
|
||||
Objects.requireNonNull(eventManager);
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(scheduler1);
|
||||
Objects.requireNonNull(scheduler2);
|
||||
|
||||
_eventManager = eventManager;
|
||||
_name = name;
|
||||
_scheduler1 = scheduler1;
|
||||
_scheduler2 = scheduler2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test()
|
||||
{
|
||||
final EventScheduler scheduler1 = _eventManager.getScheduler(_scheduler1);
|
||||
final EventScheduler scheduler2 = _eventManager.getScheduler(_scheduler2);
|
||||
if (scheduler1 == null)
|
||||
{
|
||||
throw new NullPointerException("Scheduler1 not found: " + _scheduler1);
|
||||
}
|
||||
else if (scheduler2 == null)
|
||||
{
|
||||
throw new NullPointerException("Scheduler2 not found: " + _scheduler2);
|
||||
}
|
||||
|
||||
final long previousStart = scheduler1.getPrevSchedule();
|
||||
final long previousEnd = scheduler2.getPrevSchedule();
|
||||
return previousStart > previousEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final EventScheduler mainScheduler = _eventManager.getScheduler(_name);
|
||||
if (mainScheduler == null)
|
||||
{
|
||||
throw new NullPointerException("Main scheduler not found: " + _name);
|
||||
}
|
||||
mainScheduler.run();
|
||||
LOGGER.info("Event " + _eventManager.getClass().getSimpleName() + " will resume because is within the event period");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.conditions;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.commons.database.DatabaseFactory;
|
||||
import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager;
|
||||
import com.l2jmobius.gameserver.model.eventengine.EventScheduler;
|
||||
import com.l2jmobius.gameserver.model.eventengine.IConditionalEventScheduler;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class HaventRunConditionalScheduler implements IConditionalEventScheduler
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(HaventRunConditionalScheduler.class.getName());
|
||||
private final AbstractEventManager<?> _eventManager;
|
||||
private final String _name;
|
||||
|
||||
public HaventRunConditionalScheduler(AbstractEventManager<?> eventManager, String name)
|
||||
{
|
||||
_eventManager = eventManager;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test()
|
||||
{
|
||||
final EventScheduler mainScheduler = _eventManager.getScheduler(_name);
|
||||
if (mainScheduler == null)
|
||||
{
|
||||
throw new NullPointerException("Scheduler not found: " + _name);
|
||||
}
|
||||
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT lastRun FROM event_schedulers WHERE eventName = ? AND schedulerName = ?"))
|
||||
{
|
||||
ps.setString(1, _eventManager.getName());
|
||||
ps.setString(2, mainScheduler.getName());
|
||||
try (ResultSet rs = ps.executeQuery())
|
||||
{
|
||||
if (rs.next())
|
||||
{
|
||||
final long lastRun = rs.getTimestamp(1).getTime();
|
||||
final long lastPossibleRun = mainScheduler.getPrevSchedule();
|
||||
return (lastPossibleRun > lastRun) && (Math.abs(lastPossibleRun - lastRun) > 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Failed to retreive information for scheduled task event manager: " + _eventManager.getClass().getSimpleName() + " scheduler: " + _name, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final EventScheduler mainScheduler = _eventManager.getScheduler(_name);
|
||||
if (mainScheduler == null)
|
||||
{
|
||||
throw new NullPointerException("Scheduler not found: " + _name);
|
||||
}
|
||||
|
||||
if (mainScheduler.updateLastRun())
|
||||
{
|
||||
mainScheduler.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class EventDropGroup
|
||||
{
|
||||
private final List<EventDropItem> _items = new ArrayList<>();
|
||||
private final double _chance;
|
||||
|
||||
public EventDropGroup(double chance)
|
||||
{
|
||||
_chance = chance;
|
||||
}
|
||||
|
||||
public double getChance()
|
||||
{
|
||||
return _chance;
|
||||
}
|
||||
|
||||
public List<EventDropItem> getItems()
|
||||
{
|
||||
return _items;
|
||||
}
|
||||
|
||||
public void addItem(EventDropItem item)
|
||||
{
|
||||
_items.add(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class EventDropItem
|
||||
{
|
||||
private final int _id;
|
||||
private final int _min;
|
||||
private final int _max;
|
||||
private final double _chance;
|
||||
|
||||
public EventDropItem(int id, int min, int max, double chance)
|
||||
{
|
||||
_id = id;
|
||||
_min = min;
|
||||
_max = max;
|
||||
_chance = chance;
|
||||
}
|
||||
|
||||
public int getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public int getMin()
|
||||
{
|
||||
return _min;
|
||||
}
|
||||
|
||||
public int getMax()
|
||||
{
|
||||
return _max;
|
||||
}
|
||||
|
||||
public double getChance()
|
||||
{
|
||||
return _chance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public enum EventDrops
|
||||
{
|
||||
GROUPED(GroupedDrop::new),
|
||||
NORMAL(NormalDrop::new);
|
||||
|
||||
private final Supplier<? extends IEventDrop> _supplier;
|
||||
|
||||
private EventDrops(Supplier<IEventDrop> supplier)
|
||||
{
|
||||
_supplier = supplier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IEventDrop> T newInstance()
|
||||
{
|
||||
return (T) (_supplier.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
import com.l2jmobius.gameserver.model.holders.ItemHolder;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class GroupedDrop implements IEventDrop
|
||||
{
|
||||
private final List<EventDropGroup> _groups = new ArrayList<>();
|
||||
|
||||
public List<EventDropGroup> getGroups()
|
||||
{
|
||||
return _groups;
|
||||
}
|
||||
|
||||
public void addGroup(EventDropGroup group)
|
||||
{
|
||||
_groups.add(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ItemHolder> calculateDrops()
|
||||
{
|
||||
final List<ItemHolder> rewards = new ArrayList<>();
|
||||
for (EventDropGroup group : _groups)
|
||||
{
|
||||
if ((Rnd.nextDouble() * 100) < group.getChance())
|
||||
{
|
||||
double totalChance = 0;
|
||||
final double random = (Rnd.nextDouble() * 100);
|
||||
for (EventDropItem item : group.getItems())
|
||||
{
|
||||
totalChance += item.getChance();
|
||||
if (totalChance > random)
|
||||
{
|
||||
final long count = Rnd.get(item.getMin(), item.getMax());
|
||||
if (count > 0)
|
||||
{
|
||||
rewards.add(new ItemHolder(item.getId(), count));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rewards;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.l2jmobius.gameserver.model.holders.ItemHolder;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public interface IEventDrop
|
||||
{
|
||||
public Collection<ItemHolder> calculateDrops();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 com.l2jmobius.gameserver.model.eventengine.drop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
import com.l2jmobius.gameserver.model.holders.ItemHolder;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class NormalDrop implements IEventDrop
|
||||
{
|
||||
private final List<EventDropItem> _items = new ArrayList<>();
|
||||
|
||||
public List<EventDropItem> getItems()
|
||||
{
|
||||
return _items;
|
||||
}
|
||||
|
||||
public void addItem(EventDropItem item)
|
||||
{
|
||||
_items.add(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ItemHolder> calculateDrops()
|
||||
{
|
||||
final List<ItemHolder> rewards = new ArrayList<>();
|
||||
double totalChance = 0;
|
||||
final double random = (Rnd.nextDouble() * 100);
|
||||
for (EventDropItem item : _items)
|
||||
{
|
||||
totalChance += item.getChance();
|
||||
if (totalChance > random)
|
||||
{
|
||||
final long count = Rnd.get(item.getMin(), item.getMax());
|
||||
if (count > 0)
|
||||
{
|
||||
rewards.add(new ItemHolder(item.getId(), count));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rewards;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user