-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlayerTimeManager.java
177 lines (139 loc) · 7.19 KB
/
PlayerTimeManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package timedCraft;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
public class PlayerTimeManager {
private static final String dataAllocatedLabel = "TimedCraft_DataAllocated";
private static final String remainingTimeLabel = "TimedCraft_RemainingTime";
private static final String lastLogoutTimeLabel = "TimedCraft_LastLogoutTime";
private static final String lastTickTimeLabel = "TimedCraft_LastTickTime";
private static final int playerNotificationInterval = 300000;
private static final int playerTimeNearlyUpNotificationTime = 60000;
private static PlayerTimeManager instance = null;
// A redundant data store that we read from whenever the player's stored
// entity data is missing, such as on respawn after death.
private Map<String, Long> cachedPlayerLastTickTime = new HashMap<String, Long>();
private Map<String, Integer> cachedPlayerTimeRemaining = new HashMap<String, Integer>();
public static PlayerTimeManager GetInstance() {
if (instance == null) {
instance = new PlayerTimeManager();
}
return instance;
}
public void OnPlayerConnect(EntityPlayer player) {
if (TimedConfiguration.Instance.PlayerHasTimeLimit(player)) {
this.EnsurePlayerDataAllocated(player);
// Credit the player for time accumulated since last login
this.AddTimeAccumulatedSinceLastLogout(player);
// Message the player with their time remaining
this.SendPlayerTimeNotification(player);
}
}
public void OnPlayerDisconnect(EntityPlayer player) {
if (TimedConfiguration.Instance.PlayerHasTimeLimit(player)) {
this.EnsurePlayerDataAllocated(player);
// Record the player's logout time
this.RecordLastLogout(player);
// Flush the last tick time
player.getEntityData().setLong(lastTickTimeLabel, 0);
}
}
public void OnPlayerTick(EntityPlayer player) {
// If we have a time limit, enforce it
if (TimedConfiguration.Instance.PlayerHasTimeLimit(player)) {
this.EnsurePlayerDataAllocated(player);
// Measure the time between ticks and update the stored last tick value
long lastTickTime = player.getEntityData().getLong(lastTickTimeLabel);
long currentTickTime = System.currentTimeMillis();
// Only tick the player if we have a last tick
if (lastTickTime > 0) {
int millisecondsSinceLastTick = (int) (currentTickTime - player.getEntityData().getLong(lastTickTimeLabel));
int previousTimeRemaining = this.GetPlayerRemainingTime(player);
this.AddTime(player, (int)(millisecondsSinceLastTick * this.GetPlayerTimeRegenerationRate(player)));
this.SubtractTime(player, millisecondsSinceLastTick);
int currentTimeRemaining = this.GetPlayerRemainingTime(player);
if (currentTimeRemaining <= 0) {
this.KickPlayer(player);
} else if (currentTimeRemaining % playerNotificationInterval > previousTimeRemaining % playerNotificationInterval) {
this.SendPlayerTimeNotification(player);
} else if (currentTimeRemaining < playerTimeNearlyUpNotificationTime && previousTimeRemaining > playerTimeNearlyUpNotificationTime) {
this.SendPlayerTimeNotification(player);
}
}
player.getEntityData().setLong(lastTickTimeLabel, currentTickTime);
this.cachedPlayerLastTickTime.put(player.username, currentTickTime);
}
}
// If the player's data is not yet allocated (which occurs either when a new player
// joins or the player dies), assign it to either a cached value if we have one or
// the defaults. Defaults are:
// - remaining time is the player's maximum daily time
// - last tick time is null
// - last logout is always null (this is zero while the player is logged in, so it doesn't matter if he dies)
private void EnsurePlayerDataAllocated(EntityPlayer player) {
boolean dataAllocated = player.getEntityData().getBoolean(dataAllocatedLabel);
if (!dataAllocated) {
TimedCraft.Logger.info(String.format("Allocating data for player %s.", player.username));
player.getEntityData().setBoolean(dataAllocatedLabel, true);
if (this.cachedPlayerTimeRemaining.containsKey(player.username)) {
player.getEntityData().setInteger(remainingTimeLabel, this.cachedPlayerTimeRemaining.get(player.username));
} else {
player.getEntityData().setInteger(remainingTimeLabel, TimedConfiguration.Instance.GetPlayerDailyTimeAllotment(player));
}
if (this.cachedPlayerLastTickTime.containsKey(player.username)) {
player.getEntityData().setLong(lastTickTimeLabel, this.cachedPlayerLastTickTime.get(player.username));
} else {
player.getEntityData().setLong(lastTickTimeLabel, 0);
}
player.getEntityData().setLong(lastLogoutTimeLabel, 0);
}
}
//
private void AddTimeAccumulatedSinceLastLogout(EntityPlayer player) {
long lastLogout = player.getEntityData().getLong(lastLogoutTimeLabel);
if (lastLogout > 0)
{
int millisecondsSinceLogout = (int)(System.currentTimeMillis() - lastLogout);
int millisecondsAccumulated = (int)(millisecondsSinceLogout * this.GetPlayerTimeRegenerationRate(player));
this.AddTime(player, millisecondsAccumulated);
// Clear the last logout
player.getEntityData().setLong(lastLogoutTimeLabel, 0);
}
}
private void RecordLastLogout(EntityPlayer player) {
player.getEntityData().setLong(lastLogoutTimeLabel, System.currentTimeMillis());
}
// Adds the given amount of time to the player, up to the per-day cap.
private void AddTime(EntityPlayer player, int milliseconds) {
int currentTimeRemaining = this.GetPlayerRemainingTime(player);
currentTimeRemaining = Math.min(currentTimeRemaining + milliseconds, TimedConfiguration.Instance.GetPlayerDailyTimeAllotment(player));
this.SetPlayerRemainingTime(player, currentTimeRemaining);
}
// Subtracts the given amount of time from the player, down to zero.
private void SubtractTime(EntityPlayer player, int milliseconds) {
int currentTimeRemaining = this.GetPlayerRemainingTime(player);
currentTimeRemaining = Math.max(currentTimeRemaining - milliseconds, 0);
this.SetPlayerRemainingTime(player, currentTimeRemaining);
}
// Gets the rate at which a player regains play time, compared to the normal passage of time.
private double GetPlayerTimeRegenerationRate(EntityPlayer player) {
return TimedConfiguration.Instance.GetPlayerDailyTimeAllotment(player) / 86400000.0;
}
// Gets the time, in milliseconds, that the player has left to be logged in.
private int GetPlayerRemainingTime(EntityPlayer player) {
return player.getEntityData().getInteger(remainingTimeLabel);
}
// Sets the player's remaining logged-in time, in milliseconds.
private void SetPlayerRemainingTime(EntityPlayer player, int milliseconds) {
player.getEntityData().setInteger(remainingTimeLabel, milliseconds);
this.cachedPlayerTimeRemaining.put(player.username, milliseconds);
}
private void SendPlayerTimeNotification(EntityPlayer player) {
int remainingTime = (int) this.GetPlayerRemainingTime(player);
player.addChatMessage(String.format("You have %d:%02d minutes of gameplay time remaining.", remainingTime / 60000, (remainingTime / 1000) % 60 ));
}
private void KickPlayer(EntityPlayer player) {
((EntityPlayerMP)player).playerNetServerHandler.kickPlayerFromServer("Your time is up!");
}
}