Event based and configurable player timeout system, visible through /f p. Also started storing the last player activity locally since the Bukkit API is broken. This will probably fix issues reported where players never get kicked.
This commit is contained in:
parent
a57f05eb1d
commit
8d285eab34
@ -1,10 +1,13 @@
|
|||||||
package com.massivecraft.factions.cmd;
|
package com.massivecraft.factions.cmd;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.massivecraft.factions.Perm;
|
import com.massivecraft.factions.Perm;
|
||||||
import com.massivecraft.factions.cmd.arg.ARMPlayer;
|
import com.massivecraft.factions.cmd.arg.ARMPlayer;
|
||||||
|
import com.massivecraft.factions.entity.MConf;
|
||||||
import com.massivecraft.factions.entity.MPlayer;
|
import com.massivecraft.factions.entity.MPlayer;
|
||||||
|
import com.massivecraft.factions.event.EventFactionsRemovePlayerMillis;
|
||||||
import com.massivecraft.massivecore.Progressbar;
|
import com.massivecraft.massivecore.Progressbar;
|
||||||
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
|
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
|
||||||
import com.massivecraft.massivecore.util.TimeDiffUtil;
|
import com.massivecraft.massivecore.util.TimeDiffUtil;
|
||||||
@ -52,17 +55,17 @@ public class CmdFactionsPlayer extends FactionsCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
int progressbarWidth = (int) Math.round(mplayer.getPowerMax() / mplayer.getPowerMaxUniversal() * 100);
|
int progressbarWidth = (int) Math.round(mplayer.getPowerMax() / mplayer.getPowerMaxUniversal() * 100);
|
||||||
msg("<k>Power: <v>%s", Progressbar.HEALTHBAR_CLASSIC.withQuota(progressbarQuota).withWidth(progressbarWidth).render());
|
msg("<a>Power: <v>%s", Progressbar.HEALTHBAR_CLASSIC.withQuota(progressbarQuota).withWidth(progressbarWidth).render());
|
||||||
|
|
||||||
// INFO: Power (as digits)
|
// INFO: Power (as digits)
|
||||||
msg("<k>Power: <v>%.2f / %.2f", mplayer.getPower(), mplayer.getPowerMax());
|
msg("<a>Power: <v>%.2f / %.2f", mplayer.getPower(), mplayer.getPowerMax());
|
||||||
|
|
||||||
// INFO: Power Boost
|
// INFO: Power Boost
|
||||||
if (mplayer.hasPowerBoost())
|
if (mplayer.hasPowerBoost())
|
||||||
{
|
{
|
||||||
double powerBoost = mplayer.getPowerBoost();
|
double powerBoost = mplayer.getPowerBoost();
|
||||||
String powerBoostType = (powerBoost > 0 ? "bonus" : "penalty");
|
String powerBoostType = (powerBoost > 0 ? "bonus" : "penalty");
|
||||||
msg("<k>Power Boost: <v>%f <i>(a manually granted %s)", powerBoost, powerBoostType);
|
msg("<a>Power Boost: <v>%f <i>(a manually granted %s)", powerBoost, powerBoostType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// INFO: Power per Hour
|
// INFO: Power per Hour
|
||||||
@ -79,11 +82,33 @@ public class CmdFactionsPlayer extends FactionsCommand
|
|||||||
stringTillMax = Txt.parse(" <i>(%s <i>left till max)", unitcountsTillMaxFormated);
|
stringTillMax = Txt.parse(" <i>(%s <i>left till max)", unitcountsTillMaxFormated);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg("<k>Power per Hour: <v>%.2f%s", mplayer.getPowerPerHour(), stringTillMax);
|
msg("<a>Power per Hour: <v>%.2f%s", mplayer.getPowerPerHour(), stringTillMax);
|
||||||
|
|
||||||
// INFO: Power per Death
|
// INFO: Power per Death
|
||||||
msg("<k>Power per Death: <v>%.2f", mplayer.getPowerPerDeath());
|
msg("<a>Power per Death: <v>%.2f", mplayer.getPowerPerDeath());
|
||||||
|
|
||||||
|
// Display automatic kick / remove info if the system is in use
|
||||||
|
if (MConf.get().removePlayerMillisDefault <= 0) return;
|
||||||
|
|
||||||
|
EventFactionsRemovePlayerMillis event = new EventFactionsRemovePlayerMillis(false, mplayer);
|
||||||
|
event.run();
|
||||||
|
msg("<i>Automatic removal after %s <i>of inactivity:", format(event.getMillis()));
|
||||||
|
for (Entry<String, Long> causeMillis : event.getCauseMillis().entrySet())
|
||||||
|
{
|
||||||
|
String cause = causeMillis.getKey();
|
||||||
|
long millis = causeMillis.getValue();
|
||||||
|
msg("<a>%s<a>: <v>%s", cause, format(millis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// TIME FORMAT
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public static String format(long millis)
|
||||||
|
{
|
||||||
|
LinkedHashMap<TimeUnit, Long> unitcounts = TimeDiffUtil.unitcounts(millis, TimeUnit.getAllBut(TimeUnit.MILLISECOND, TimeUnit.WEEK, TimeUnit.MONTH));
|
||||||
|
return TimeDiffUtil.formatedVerboose(unitcounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1103,7 +1103,8 @@ public class Faction extends Entity<Faction> implements EconomyParticipator
|
|||||||
this.detach();
|
this.detach();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // promote new faction leader
|
{
|
||||||
|
// promote new faction leader
|
||||||
if (oldLeader != null)
|
if (oldLeader != null)
|
||||||
{
|
{
|
||||||
oldLeader.setRole(Rel.MEMBER);
|
oldLeader.setRole(Rel.MEMBER);
|
||||||
|
@ -20,6 +20,7 @@ import com.massivecraft.factions.integration.dynmap.DynmapStyle;
|
|||||||
import com.massivecraft.factions.listeners.FactionsListenerChat;
|
import com.massivecraft.factions.listeners.FactionsListenerChat;
|
||||||
import com.massivecraft.massivecore.store.Entity;
|
import com.massivecraft.massivecore.store.Entity;
|
||||||
import com.massivecraft.massivecore.util.MUtil;
|
import com.massivecraft.massivecore.util.MUtil;
|
||||||
|
import com.massivecraft.massivecore.util.TimeUnit;
|
||||||
|
|
||||||
public class MConf extends Entity<MConf>
|
public class MConf extends Entity<MConf>
|
||||||
{
|
{
|
||||||
@ -79,8 +80,21 @@ public class MConf extends Entity<MConf>
|
|||||||
// REMOVE DATA
|
// REMOVE DATA
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public boolean removePlayerDataWhenBanned = true;
|
public boolean removePlayerWhenBanned = true;
|
||||||
public double removePlayerDataAfterInactiveDays = 20.0;
|
|
||||||
|
// The Default
|
||||||
|
public long removePlayerMillisDefault = 10 * TimeUnit.MILLIS_PER_DAY;
|
||||||
|
|
||||||
|
// Player Age Bonus
|
||||||
|
public Map<Long, Long> removePlayerMillisPlayerAgeToBonus = MUtil.map(
|
||||||
|
2 * TimeUnit.MILLIS_PER_WEEK, 10 * TimeUnit.MILLIS_PER_DAY // +10 after 2 weeks
|
||||||
|
);
|
||||||
|
|
||||||
|
// Faction Age Bonus
|
||||||
|
public Map<Long, Long> removePlayerMillisFactionAgeToBonus = MUtil.map(
|
||||||
|
4 * TimeUnit.MILLIS_PER_WEEK, 10 * TimeUnit.MILLIS_PER_DAY, // +10 after 4 weeks
|
||||||
|
2 * TimeUnit.MILLIS_PER_WEEK, 5 * TimeUnit.MILLIS_PER_DAY // +5 after 2 weeks
|
||||||
|
);
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// SPECIAL FACTION IDS
|
// SPECIAL FACTION IDS
|
||||||
|
@ -14,6 +14,7 @@ import com.massivecraft.factions.Rel;
|
|||||||
import com.massivecraft.factions.RelationParticipator;
|
import com.massivecraft.factions.RelationParticipator;
|
||||||
import com.massivecraft.factions.event.EventFactionsChunkChange;
|
import com.massivecraft.factions.event.EventFactionsChunkChange;
|
||||||
import com.massivecraft.factions.event.EventFactionsMembershipChange;
|
import com.massivecraft.factions.event.EventFactionsMembershipChange;
|
||||||
|
import com.massivecraft.factions.event.EventFactionsRemovePlayerMillis;
|
||||||
import com.massivecraft.factions.event.EventFactionsMembershipChange.MembershipChangeReason;
|
import com.massivecraft.factions.event.EventFactionsMembershipChange.MembershipChangeReason;
|
||||||
import com.massivecraft.factions.util.RelationUtil;
|
import com.massivecraft.factions.util.RelationUtil;
|
||||||
import com.massivecraft.massivecore.mixin.Mixin;
|
import com.massivecraft.massivecore.mixin.Mixin;
|
||||||
@ -43,6 +44,7 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
|
|||||||
@Override
|
@Override
|
||||||
public MPlayer load(MPlayer that)
|
public MPlayer load(MPlayer that)
|
||||||
{
|
{
|
||||||
|
this.setLastActivityMillis(that.lastActivityMillis);
|
||||||
this.setFactionId(that.factionId);
|
this.setFactionId(that.factionId);
|
||||||
this.setRole(that.role);
|
this.setRole(that.role);
|
||||||
this.setTitle(that.title);
|
this.setTitle(that.title);
|
||||||
@ -57,11 +59,13 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
|
|||||||
@Override
|
@Override
|
||||||
public boolean isDefault()
|
public boolean isDefault()
|
||||||
{
|
{
|
||||||
|
// Last activity millis is data we use for clearing out inactive players. So it does not in itself make the player data worth keeping.
|
||||||
if (this.hasFaction()) return false;
|
if (this.hasFaction()) return false;
|
||||||
// Role means nothing without a faction.
|
// Role means nothing without a faction.
|
||||||
// Title means nothing without a faction.
|
// Title means nothing without a faction.
|
||||||
|
if (this.hasPowerBoost()) return false;
|
||||||
if (this.getPowerRounded() != (int) Math.round(MConf.get().defaultPlayerPower)) return false;
|
if (this.getPowerRounded() != (int) Math.round(MConf.get().defaultPlayerPower)) return false;
|
||||||
if (this.isMapAutoUpdating()) return false;
|
// if (this.isMapAutoUpdating()) return false; // Just having an auto updating map is not in itself reason enough for database storage.
|
||||||
if (this.isUsingAdminMode()) return false;
|
if (this.isUsingAdminMode()) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -99,6 +103,12 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
|
|||||||
// In this section of the source code we place the field declarations only.
|
// In this section of the source code we place the field declarations only.
|
||||||
// Each field has it's own section further down since just the getter and setter logic takes up quite some place.
|
// Each field has it's own section further down since just the getter and setter logic takes up quite some place.
|
||||||
|
|
||||||
|
// The last known time of explicit player activity, such as login or logout.
|
||||||
|
// Null means "unknown" (as opposed to "never played on the server").
|
||||||
|
// The player might have been active very recently but we could lack that data.
|
||||||
|
// The reason being this data field was added in a version upgrade and has not been around for forever.
|
||||||
|
private Long lastActivityMillis = null;
|
||||||
|
|
||||||
// This is a foreign key.
|
// This is a foreign key.
|
||||||
// Each player belong to a faction.
|
// Each player belong to a faction.
|
||||||
// Null means default.
|
// Null means default.
|
||||||
@ -158,6 +168,46 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
|
|||||||
this.setAutoClaimFaction(null);
|
this.setAutoClaimFaction(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// FIELD: lastActivityMillis
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
// Raw: Using only what we have stored
|
||||||
|
|
||||||
|
public Long getLastActivityMillisRaw()
|
||||||
|
{
|
||||||
|
return this.lastActivityMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastActivityMillis(Long lastActivityMillis)
|
||||||
|
{
|
||||||
|
// Clean input
|
||||||
|
Long target = lastActivityMillis;
|
||||||
|
|
||||||
|
// Detect Nochange
|
||||||
|
if (MUtil.equals(this.lastActivityMillis, target)) return;
|
||||||
|
|
||||||
|
// Apply
|
||||||
|
this.lastActivityMillis = target;
|
||||||
|
|
||||||
|
// Mark as changed
|
||||||
|
this.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastActivityMillis()
|
||||||
|
{
|
||||||
|
this.setLastActivityMillis(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finer: Using our raw data but also underlying system as fallback
|
||||||
|
|
||||||
|
public Long getLastActivityMillis()
|
||||||
|
{
|
||||||
|
Long ret = this.getLastActivityMillisRaw();
|
||||||
|
if (ret != null) return ret;
|
||||||
|
return Mixin.getLastPlayed(this);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// FIELD: factionId
|
// FIELD: factionId
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
@ -625,6 +675,57 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
|
|||||||
return BoardColl.get().getFactionAt(ps).getRelationTo(this) == Rel.ENEMY;
|
return BoardColl.get().getFactionAt(ps).getRelationTo(this) == Rel.ENEMY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// INACTIVITY TIMEOUT
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public long getRemovePlayerMillis(boolean async)
|
||||||
|
{
|
||||||
|
EventFactionsRemovePlayerMillis event = new EventFactionsRemovePlayerMillis(async, this);
|
||||||
|
event.run();
|
||||||
|
return event.getMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean considerRemovePlayerMillis(boolean async)
|
||||||
|
{
|
||||||
|
// This may or may not be required.
|
||||||
|
// Some users have been reporting a loop issue with the same player detaching over and over again.
|
||||||
|
// Maybe skipping ahead if the player is detached will solve the issue.
|
||||||
|
if (this.detached()) return false;
|
||||||
|
|
||||||
|
// Get the last activity millis.
|
||||||
|
// Null means "unknown" in which case we does nothing.
|
||||||
|
Long lastActivityMillis = this.getLastActivityMillis();
|
||||||
|
if (lastActivityMillis == null) return false;
|
||||||
|
|
||||||
|
// Consider
|
||||||
|
long toleranceMillis = this.getRemovePlayerMillis(async);
|
||||||
|
if (System.currentTimeMillis() - lastActivityMillis <= toleranceMillis) return false;
|
||||||
|
|
||||||
|
// Inform
|
||||||
|
if (MConf.get().logFactionLeave || MConf.get().logFactionKick)
|
||||||
|
{
|
||||||
|
Factions.get().log("Player " + this.getName() + " was auto-removed due to inactivity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply
|
||||||
|
|
||||||
|
// Promote a new leader if required.
|
||||||
|
if (this.getRole() == Rel.LEADER)
|
||||||
|
{
|
||||||
|
Faction faction = this.getFaction();
|
||||||
|
if (faction != null)
|
||||||
|
{
|
||||||
|
this.getFaction().promoteNewLeader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.leave();
|
||||||
|
this.detach();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// ACTIONS
|
// ACTIONS
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package com.massivecraft.factions.entity;
|
package com.massivecraft.factions.entity;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
import com.massivecraft.factions.Const;
|
import com.massivecraft.factions.Const;
|
||||||
import com.massivecraft.factions.Factions;
|
import com.massivecraft.factions.Factions;
|
||||||
import com.massivecraft.factions.Rel;
|
|
||||||
import com.massivecraft.massivecore.mixin.Mixin;
|
|
||||||
import com.massivecraft.massivecore.store.MStore;
|
import com.massivecraft.massivecore.store.MStore;
|
||||||
import com.massivecraft.massivecore.store.SenderColl;
|
import com.massivecraft.massivecore.store.SenderColl;
|
||||||
import com.massivecraft.massivecore.util.IdUtil;
|
import com.massivecraft.massivecore.util.IdUtil;
|
||||||
import com.massivecraft.massivecore.util.TimeUnit;
|
|
||||||
import com.massivecraft.massivecore.util.Txt;
|
import com.massivecraft.massivecore.util.Txt;
|
||||||
|
|
||||||
public class MPlayerColl extends SenderColl<MPlayer>
|
public class MPlayerColl extends SenderColl<MPlayer>
|
||||||
@ -41,87 +42,27 @@ public class MPlayerColl extends SenderColl<MPlayer>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayerDataAfterInactiveDaysRoutine()
|
public void considerRemovePlayerMillis()
|
||||||
{
|
{
|
||||||
if (MConf.get().removePlayerDataAfterInactiveDays <= 0.0) return;
|
// If the config option is 0 or below that means the server owner want it disabled.
|
||||||
|
if (MConf.get().removePlayerMillisDefault <= 0.0) return;
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
// For each of the offline players...
|
||||||
double toleranceMillis = MConf.get().removePlayerDataAfterInactiveDays * TimeUnit.MILLIS_PER_DAY;
|
// NOTE: If the player is currently online it's most definitely not inactive.
|
||||||
|
// NOTE: This check catches some important special cases like the @console "player".
|
||||||
|
final Collection<MPlayer> mplayersOffline = this.getAllOffline();
|
||||||
|
|
||||||
for (MPlayer mplayer : this.getAll())
|
Bukkit.getScheduler().runTaskAsynchronously(Factions.get(), new Runnable()
|
||||||
{
|
{
|
||||||
// This may or may not be required.
|
@Override
|
||||||
// Some users have been reporting a loop issue with the same player detaching over and over again.
|
public void run()
|
||||||
// Maybe skipping ahead if the player is detached will solve the issue.
|
|
||||||
if (mplayer.detached()) continue;
|
|
||||||
|
|
||||||
if (mplayer.isOnline()) continue;
|
|
||||||
|
|
||||||
Long lastPlayed = Mixin.getLastPlayed(mplayer.getId());
|
|
||||||
if (lastPlayed == null) continue;
|
|
||||||
if (now - lastPlayed <= toleranceMillis) continue;
|
|
||||||
|
|
||||||
if (MConf.get().logFactionLeave || MConf.get().logFactionKick)
|
|
||||||
{
|
{
|
||||||
Factions.get().log("Player "+mplayer.getName()+" was auto-removed due to inactivity.");
|
for (MPlayer mplayer : mplayersOffline)
|
||||||
}
|
|
||||||
|
|
||||||
// if player is faction leader, sort out the faction since he's going away
|
|
||||||
if (mplayer.getRole() == Rel.LEADER)
|
|
||||||
{
|
{
|
||||||
Faction faction = mplayer.getFaction();
|
mplayer.considerRemovePlayerMillis(true);
|
||||||
if (faction != null)
|
|
||||||
{
|
|
||||||
mplayer.getFaction().promoteNewLeader();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
mplayer.leave();
|
|
||||||
mplayer.detach();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// This method is for the 1.8.X --> 2.0.0 migration
|
|
||||||
public void migrate()
|
|
||||||
{
|
|
||||||
// Create file objects
|
|
||||||
File oldFile = new File(Factions.get().getDataFolder(), "players.json");
|
|
||||||
File newFile = new File(Factions.get().getDataFolder(), "players.json.migrated");
|
|
||||||
|
|
||||||
// Already migrated?
|
|
||||||
if ( ! oldFile.exists()) return;
|
|
||||||
|
|
||||||
// Read the file content through GSON.
|
|
||||||
Type type = new TypeToken<Map<String, MPlayer>>(){}.getType();
|
|
||||||
Map<String, MPlayer> id2mplayer = Factions.get().gson.fromJson(DiscUtil.readCatch(oldFile), type);
|
|
||||||
|
|
||||||
// The Coll
|
|
||||||
MPlayerColl coll = this.getForUniverse(MassiveCore.DEFAULT);
|
|
||||||
|
|
||||||
// Set the data
|
|
||||||
for (Entry<String, MPlayer> entry : id2mplayer.entrySet())
|
|
||||||
{
|
|
||||||
String playerId = entry.getKey();
|
|
||||||
MPlayer mplayer = entry.getValue();
|
|
||||||
coll.attach(mplayer, playerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark as migrated
|
|
||||||
oldFile.renameTo(newFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// EXTRAS
|
|
||||||
// -------------------------------------------- //
|
|
||||||
|
|
||||||
public void clean()
|
|
||||||
{
|
|
||||||
for (MPlayerColl coll : this.getColls())
|
|
||||||
{
|
|
||||||
coll.clean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
package com.massivecraft.factions.event;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
import com.massivecraft.factions.entity.Faction;
|
||||||
|
import com.massivecraft.factions.entity.MConf;
|
||||||
|
import com.massivecraft.factions.entity.MPlayer;
|
||||||
|
import com.massivecraft.massivecore.event.EventMassiveCore;
|
||||||
|
|
||||||
|
public class EventFactionsRemovePlayerMillis extends EventMassiveCore
|
||||||
|
{
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// REQUIRED EVENT CODE
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
@Override public HandlerList getHandlers() { return handlers; }
|
||||||
|
public static HandlerList getHandlerList() { return handlers; }
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// FIELD
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
private final MPlayer mplayer;
|
||||||
|
public MPlayer getMPlayer() { return this.mplayer; }
|
||||||
|
|
||||||
|
private long millis;
|
||||||
|
public long getMillis() { return this.millis; }
|
||||||
|
public void setMillis(long millis) { this.millis = millis; }
|
||||||
|
|
||||||
|
private Map<String, Long> causeMillis = new LinkedHashMap<String, Long>();
|
||||||
|
public Map<String, Long> getCauseMillis() { return this.causeMillis; }
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// CONSTRUCT
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public EventFactionsRemovePlayerMillis(boolean async, MPlayer mplayer)
|
||||||
|
{
|
||||||
|
super(async);
|
||||||
|
|
||||||
|
this.mplayer = mplayer;
|
||||||
|
this.millis = MConf.get().removePlayerMillisDefault;
|
||||||
|
|
||||||
|
// Default
|
||||||
|
this.causeMillis.put("Default", MConf.get().removePlayerMillisDefault);
|
||||||
|
|
||||||
|
// Player Age Bonus
|
||||||
|
this.applyPlayerAgeBonus();
|
||||||
|
|
||||||
|
// Faction Age Bonus
|
||||||
|
this.applyFactionAgeBonus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// UTIL
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public void applyPlayerAgeBonus()
|
||||||
|
{
|
||||||
|
// Skip if this bonus is totally disabled.
|
||||||
|
// We don't want it showing up with 0 for everyone.
|
||||||
|
if (MConf.get().removePlayerMillisPlayerAgeToBonus.isEmpty()) return;
|
||||||
|
|
||||||
|
// Calculate First Played
|
||||||
|
Long firstPlayed = this.getMPlayer().getFirstPlayed();
|
||||||
|
Long age = 0L;
|
||||||
|
if (firstPlayed != null)
|
||||||
|
{
|
||||||
|
age = System.currentTimeMillis() - firstPlayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the Bonus!
|
||||||
|
long bonus = 0;
|
||||||
|
for (Entry<Long, Long> entry : MConf.get().removePlayerMillisPlayerAgeToBonus.entrySet())
|
||||||
|
{
|
||||||
|
Long key = entry.getKey();
|
||||||
|
if (key == null) continue;
|
||||||
|
|
||||||
|
Long value = entry.getValue();
|
||||||
|
if (value == null) continue;
|
||||||
|
|
||||||
|
if (age >= key)
|
||||||
|
{
|
||||||
|
bonus = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply
|
||||||
|
this.setMillis(this.getMillis() + bonus);
|
||||||
|
|
||||||
|
// Inform
|
||||||
|
this.getCauseMillis().put("Player Age Bonus", bonus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyFactionAgeBonus()
|
||||||
|
{
|
||||||
|
// Skip if this bonus is totally disabled.
|
||||||
|
// We don't want it showing up with 0 for everyone.
|
||||||
|
if (MConf.get().removePlayerMillisFactionAgeToBonus.isEmpty()) return;
|
||||||
|
|
||||||
|
// Calculate Faction Age
|
||||||
|
Faction faction = this.getMPlayer().getFaction();
|
||||||
|
long age = 0;
|
||||||
|
if ( ! faction.isNone())
|
||||||
|
{
|
||||||
|
age = System.currentTimeMillis() - faction.getCreatedAtMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the Bonus!
|
||||||
|
long bonus = 0;
|
||||||
|
for (Entry<Long, Long> entry : MConf.get().removePlayerMillisFactionAgeToBonus.entrySet())
|
||||||
|
{
|
||||||
|
Long key = entry.getKey();
|
||||||
|
if (key == null) continue;
|
||||||
|
|
||||||
|
Long value = entry.getValue();
|
||||||
|
if (value == null) continue;
|
||||||
|
|
||||||
|
if (age >= key)
|
||||||
|
{
|
||||||
|
bonus = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply
|
||||||
|
this.setMillis(this.getMillis() + bonus);
|
||||||
|
|
||||||
|
// Inform
|
||||||
|
this.getCauseMillis().put("Faction Age Bonus", bonus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,6 +11,7 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Enderman;
|
import org.bukkit.entity.Enderman;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
@ -71,6 +72,7 @@ import com.massivecraft.factions.event.EventFactionsPvpDisallowed;
|
|||||||
import com.massivecraft.factions.event.EventFactionsPowerChange;
|
import com.massivecraft.factions.event.EventFactionsPowerChange;
|
||||||
import com.massivecraft.factions.event.EventFactionsPowerChange.PowerChangeReason;
|
import com.massivecraft.factions.event.EventFactionsPowerChange.PowerChangeReason;
|
||||||
import com.massivecraft.factions.util.VisualizeUtil;
|
import com.massivecraft.factions.util.VisualizeUtil;
|
||||||
|
import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave;
|
||||||
import com.massivecraft.massivecore.mixin.Mixin;
|
import com.massivecraft.massivecore.mixin.Mixin;
|
||||||
import com.massivecraft.massivecore.ps.PS;
|
import com.massivecraft.massivecore.ps.PS;
|
||||||
import com.massivecraft.massivecore.util.MUtil;
|
import com.massivecraft.massivecore.util.MUtil;
|
||||||
@ -96,6 +98,49 @@ public class FactionsListenerMain implements Listener
|
|||||||
Bukkit.getPluginManager().registerEvents(this, Factions.get());
|
Bukkit.getPluginManager().registerEvents(this, Factions.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// UPDATE LAST ACTIVITY
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public static void updateLastActivity(CommandSender sender)
|
||||||
|
{
|
||||||
|
if (sender == null) throw new RuntimeException("sender");
|
||||||
|
MPlayer mplayer = MPlayer.get(sender);
|
||||||
|
mplayer.setLastActivityMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateLastActivitySoon(final CommandSender sender)
|
||||||
|
{
|
||||||
|
if (sender == null) throw new RuntimeException("sender");
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(Factions.get(), new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
updateLastActivity(sender);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't be cancelled
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void updateLastActivity(PlayerJoinEvent event)
|
||||||
|
{
|
||||||
|
// During the join event itself we want to be able to reach the old data.
|
||||||
|
// That is also the way the underlying fallback Mixin system does it and we do it that way for the sake of symmetry.
|
||||||
|
// For that reason we wait till the next tick with updating the value.
|
||||||
|
updateLastActivitySoon(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't be cancelled
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void updateLastActivity(EventMassiveCorePlayerLeave event)
|
||||||
|
{
|
||||||
|
// Here we do however update immediately.
|
||||||
|
// The player data should be fully updated before leaving the server.
|
||||||
|
updateLastActivity(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// MOTD
|
// MOTD
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
@ -512,7 +557,7 @@ public class FactionsListenerMain implements Listener
|
|||||||
if (!player.isBanned()) return;
|
if (!player.isBanned()) return;
|
||||||
|
|
||||||
// ... and we remove player data when banned ...
|
// ... and we remove player data when banned ...
|
||||||
if (!MConf.get().removePlayerDataWhenBanned) return;
|
if (!MConf.get().removePlayerWhenBanned) return;
|
||||||
|
|
||||||
// ... get rid of their stored info.
|
// ... get rid of their stored info.
|
||||||
MPlayer mplayer = MPlayerColl.get().get(player, false);
|
MPlayer mplayer = MPlayerColl.get().get(player, false);
|
||||||
|
@ -33,7 +33,7 @@ public class TaskPlayerDataRemove extends ModuloRepeatTask
|
|||||||
@Override
|
@Override
|
||||||
public void invoke(long now)
|
public void invoke(long now)
|
||||||
{
|
{
|
||||||
MPlayerColl.get().removePlayerDataAfterInactiveDaysRoutine();
|
MPlayerColl.get().considerRemovePlayerMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user