1 /*
2  * Copyright (c) 2017-2019 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2017-2019 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/event/node/player.d, selery/event/node/player.d)
28  */
29 module selery.event.node.player;
30 
31 import std.conv : to;
32 
33 import selery.about : Software;
34 import selery.event.event : Cancellable;
35 import selery.event.node.server : NodeServerEvent;
36 import selery.hncom.player : Add, Remove;
37 import selery.node.server : NodeServer;
38 import selery.player.player : PlayerInfo, Player;
39 import selery.world.world : WorldInfo, World;
40 
41 class PlayerEvent : NodeServerEvent {
42 
43 	private const(PlayerInfo) _player;
44 
45 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player) {
46 		super(server);
47 		this._player = player;
48 	}
49 
50 	public final pure nothrow @property @safe @nogc const(PlayerInfo) player() {
51 		return this._player;
52 	}
53 
54 }
55 
56 /**
57  * Event called after the Player class for the now logged in player is created.
58  * It's the first event called after the creation of the player, before PlayerPreSpawnEvent.
59  * While this event is handled the client will see the "loading world" screen in its device,
60  * waiting for the chunks that will be sent after PlayerPreSpawnEvent (that is called by
61  * the world and every time a player changes world). That also means that this event
62  * will be called only once per player-session.
63  */
64 final class PlayerJoinEvent : PlayerEvent {
65 	
66 	enum Reason : ubyte {
67 		
68 		firstJoin = Add.FIRST_JOIN,
69 		transferred = Add.TRANSFERRED,
70 		forciblyTransferred = Add.FORCIBLY_TRANSFERRED
71 		
72 	}
73 
74 	private immutable ubyte _reason;
75 
76 	public shared(WorldInfo) world;
77 	
78 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player, ubyte reason) {
79 		super(server, player);
80 		this._reason = reason;
81 	}
82 
83 	public pure nothrow @property @safe @nogc ubyte reason() {
84 		return this._reason;
85 	}
86 	
87 }
88 
89 /**
90  * Event called when a player leaves the server, after PlayerDespawnEvent.
91  * It's the last event called for the player, after it lefts the server, and
92  * is only called once, like PlayerJoinEvent.
93  * Example:
94  * ---
95  * @effect playerleft(PlayerLeftEvent event) {
96  *    assert(!event.player.online);
97  * }
98  * ---
99  */
100 final class PlayerLeftEvent : PlayerEvent {
101 	
102 	enum Reason : ubyte {
103 		
104 		left = Remove.LEFT,
105 		timedOut = Remove.TIMED_OUT,
106 		kicked = Remove.KICKED,
107 		transferred = Remove.TRANSFERRED
108 		
109 	}
110 
111 	private immutable ubyte _reason;
112 	
113 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player, ubyte reason) {
114 		super(server, player);
115 		this._reason = reason;
116 	}
117 	
118 	public pure nothrow @property @safe @nogc ubyte reason() {
119 		return this._reason;
120 	}
121 	
122 }
123 
124 /**
125  * Event called when the player's language is updated (from the client or from
126  * a plugin). The old and the new languages will always be one in the server's accepted
127  * ones, as indicated in the hub's configuration file (accepted-languages field).
128  * Example:
129  * ---
130  * @event changeLanguage(PlayerLanguageUpdatedEvent event) {
131  *    log(event.player.name, " is changing language from ", event.currentLanguage, " to ", event.newLanguage);
132  * }
133  * ---
134  */
135 final class PlayerLanguageUpdatedEvent : PlayerEvent, Cancellable {
136 	
137 	mixin Cancellable.Implementation;
138 
139 	public immutable string oldLanguage;
140 	public immutable string newLanguage;
141 	
142 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player, string lang) {
143 		super(server, player);
144 		this.oldLanguage = player.language;
145 		this.newLanguage = lang;
146 	}
147 	
148 }
149 
150 /**
151  * Event called when the player's latency is updated from the hub.
152  * Example:
153  * ---
154  * @event updateLatency(PlayerLatencyUpdatedEvent event) {
155  *    event.player.title = event.latency.to!string ~ " ms";
156  * }
157  * ---
158  */
159 final class PlayerLatencyUpdatedEvent : PlayerEvent {
160 
161 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player) {
162 		super(server, player);
163 	}
164 
165 	/**
166 	 * Gets the player's latency.
167 	 * Example:
168 	 * ---
169 	 * assert(event.latency == event.player.latency);
170 	 * ---
171 	 */
172 	public pure nothrow @property @safe @nogc uint latency() {
173 		return this.player.latency;
174 	}
175 
176 }
177 
178 /**
179  * Event called when the player's packet loss is updated from the hub.
180  * The packet loss is only calculated for players that use a connectionless
181  * protocol like UDP (only Minecraft: Pocket Edition).
182  * Example:
183  * ---
184  * @event updatePacketLoss(PlayerPacketLossUpdatedEvent event) {
185  *    event.player.title = event.packetLoss.to!string ~ "%";
186  *    assert(event.player.pe);
187  * }
188  * ---
189  */
190 final class PlayerPacketLossUpdatedEvent : PlayerEvent {
191 
192 	public pure nothrow @safe @nogc this(shared NodeServer server, inout PlayerInfo player) {
193 		super(server, player);
194 	}
195 
196 	/**
197 	 * Gets the player's packet loss.
198 	 * Example:
199 	 * ---
200 	 * assert(event.packetLoss == event.player.packetLoss);
201 	 * ---
202 	 */
203 	public pure nothrow @property @safe @nogc float packetLoss() {
204 		return this.player.packetLoss;
205 	}
206 
207 }