1 /* 2 * Copyright (c) 2017-2018 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: 2017-2018 sel-project 25 * License: MIT 26 * Authors: Kripth 27 * Source: $(HTTP github.com/sel-project/selery/source/selery/event/world/player.d, selery/event/world/player.d) 28 */ 29 module selery.event.world.player; 30 31 import selery.block.block : Block; 32 import selery.entity.entity : Entity; 33 import selery.event.event : Cancellable; 34 import selery.event.world.damage : EntityDamageEvent; 35 import selery.event.world.entity : EntityDeathEvent; 36 import selery.event.world.world; 37 import selery.item : Slot, Item; 38 import selery.lang : Translation; 39 import selery.log : Message, Format; 40 import selery.math.vector : BlockPosition, EntityPosition, ChunkPosition; 41 import selery.player.player : Player; 42 import selery.world.world : World; 43 44 /** 45 * General player event 46 * It can be listened by world and players 47 */ 48 interface PlayerEvent : WorldEvent { 49 50 public pure nothrow @property @safe @nogc Player player(); 51 52 public static mixin template Implementation() { 53 54 //mixin WorldEvent.Implementation; 55 56 private Player n_player; 57 58 public final override pure nothrow @property @safe @nogc Player player() { 59 return this.n_player; 60 } 61 62 public final override pure nothrow @property @safe @nogc World world() { 63 // override WorldEvent.Implementation to return World from Player.world 64 return this.player.world; 65 } 66 67 } 68 69 } 70 71 /** General announce event */ 72 abstract class PlayerAnnounceEvent : PlayerEvent { 73 74 mixin PlayerEvent.Implementation; 75 76 private Message[] def; 77 private Message[] m_message; 78 79 public @safe @nogc this(Player player, Message[] message) { 80 this.n_player = player; 81 this.m_message = this.def = message; 82 } 83 84 public final pure nothrow @property @safe @nogc Message[] message() { 85 return this.m_message; 86 } 87 88 public final pure nothrow @property @safe @nogc Message[] message(Message[] message) { 89 return this.m_message = message; 90 } 91 92 public final @property Message[] message(string message) { 93 return this.m_message = [Message(message)]; 94 } 95 96 public final @property @safe Message[] message(bool display) { 97 if(display) this.m_message = this.def; 98 else this.m_message.length = 0; 99 return this.m_message; 100 } 101 102 public final pure nothrow @property @safe @nogc bool announce() { 103 return this.m_message.length > 0; 104 } 105 106 public final @property @safe bool announce(bool announce) { 107 this.message = announce; 108 return this.announce; 109 } 110 111 } 112 113 /** Called when a player spawns, but it isn't spawned to the other entities/players yet */ 114 final class PlayerSpawnEvent : PlayerAnnounceEvent { 115 116 public bool spawn = true; 117 118 public this(Player player) { 119 super(player, Message.convert(Format.yellow, Translation("multiplayer.player.joined", player.displayName))); 120 } 121 122 } 123 124 /** Called when a player leaves the world, but it isn't despawned to the other entities/players yet */ 125 final class PlayerDespawnEvent : PlayerAnnounceEvent { 126 127 public this(Player player) { 128 super(player, Message.convert(Format.yellow, Translation("multiplayer.player.left", player.displayName))); 129 } 130 131 } 132 133 /** Called when the respawn button is clicked */ 134 final class PlayerRespawnEvent : PlayerEvent, Cancellable { 135 136 mixin Cancellable.Implementation; 137 138 mixin PlayerEvent.Implementation; 139 140 public @safe @nogc this(Player player) { 141 this.n_player = player; 142 } 143 144 } 145 146 /** 147 * Called when a player sends a chat message 148 * Example: 149 * --- 150 * public @event void chat(PlayerChatEvent event) { 151 * 152 * // <player> message 153 * event.format = (string name, string message){ return "<" ~ name ~ "> " ~ message; }; 154 * 155 * // player: message 156 * event.format = (string name, string message){ return name ~ ": " ~ message; }; 157 * 158 * // replace bad words 159 * event.message = event.message.replaceAll(ctRegex!("fuck", "i"), "f**k"); 160 * 161 * } 162 * --- 163 */ 164 final class PlayerChatEvent : PlayerEvent, Cancellable { 165 166 mixin Cancellable.Implementation; 167 168 mixin PlayerEvent.Implementation; 169 170 public string message; 171 public string delegate(string, string) format; 172 173 public pure nothrow @safe @nogc this(Player player, string message) { 174 this.n_player = player; 175 this.message = message; 176 } 177 178 } 179 180 /** 181 * Player movement, called when a player sends a movement packet 182 */ 183 final class PlayerMoveEvent : PlayerEvent, Cancellable { 184 185 mixin Cancellable.Implementation; 186 187 mixin PlayerEvent.Implementation; 188 189 private EntityPosition n_position; 190 private float n_yaw, n_body_yaw, n_pitch; 191 private bool mov_in_space = true; 192 193 public @safe this(Player player, EntityPosition position, float yaw, float bodyYaw, float pitch) { 194 this.n_player = player; 195 this.n_position = position; 196 this.n_yaw = yaw % 360; 197 this.n_body_yaw = bodyYaw % 360; 198 this.n_pitch = pitch < -90 ? -90 : (pitch > 90 ? 90 : pitch); 199 if(player.position == position) { 200 this.mov_in_space = false; 201 } 202 } 203 204 public @property @safe @nogc EntityPosition position() { 205 return this.n_position; 206 } 207 208 public @property @safe @nogc float yaw() { 209 return this.n_yaw; 210 } 211 212 public @property @safe @nogc float bodyYaw() { 213 return this.n_body_yaw; 214 } 215 216 public @property @safe @nogc float pitch() { 217 return this.n_pitch; 218 } 219 220 public @property @safe @nogc bool rotation() { 221 return !this.mov_in_space; 222 } 223 224 public @property @safe @nogc bool space() { 225 return this.mov_in_space; 226 } 227 228 } 229 230 /** Called when a player hits the jump button */ 231 final class PlayerJumpEvent : PlayerEvent { 232 233 mixin PlayerEvent.Implementation; 234 235 public @safe @nogc this(Player player) { 236 this.n_player = player; 237 } 238 239 } 240 241 abstract class PlayerSprintingEvent : PlayerEvent, Cancellable { 242 243 mixin Cancellable.Implementation; 244 245 mixin PlayerEvent.Implementation; 246 247 public @safe @nogc this(Player player) { 248 this.n_player = player; 249 } 250 251 } 252 253 final class PlayerStartSprintingEvent : PlayerSprintingEvent { 254 255 public @safe @nogc this(Player player) { 256 super(player); 257 } 258 259 } 260 261 final class PlayerStopSprintingEvent : PlayerSprintingEvent { 262 263 public @safe @nogc this(Player player) { 264 super(player); 265 } 266 267 } 268 269 abstract class PlayerSneakingEvent : PlayerEvent, Cancellable { 270 271 mixin Cancellable.Implementation; 272 273 mixin PlayerEvent.Implementation; 274 275 public @safe @nogc this(Player player) { 276 this.n_player = player; 277 } 278 279 } 280 281 final class PlayerStartSneakingEvent : PlayerSneakingEvent { 282 283 public @safe @nogc this(Player player) { 284 super(player); 285 } 286 287 } 288 289 final class PlayerStopSneakingEvent : PlayerSneakingEvent { 290 291 public @safe @nogc this(Player player) { 292 super(player); 293 } 294 295 } 296 297 final class PlayerDeathEvent : EntityDeathEvent, PlayerEvent { 298 299 private Player n_player; 300 301 public @safe @nogc this(Player player, EntityDamageEvent cause) { 302 super(player, cause); 303 this.message = true; 304 this.n_player = player; 305 } 306 307 public override pure nothrow @property @safe @nogc Player player() { 308 return this.n_player; 309 } 310 311 } 312 313 final class PlayerAnimationEvent : PlayerEvent, Cancellable { 314 315 mixin Cancellable.Implementation; 316 317 mixin PlayerEvent.Implementation; 318 319 public @safe @nogc this(Player player) { 320 this.n_player = player; 321 } 322 323 } 324 325 final class PlayerUpdateViewDistanceEvent : PlayerEvent { 326 327 mixin PlayerEvent.Implementation; 328 329 private uint n_from; 330 public uint to; 331 332 public @safe @nogc this(Player player, uint from, uint to) { 333 this.n_player = player; 334 this.n_from = from; 335 this.to = to; 336 } 337 338 public @property @safe @nogc uint from() { 339 return this.n_from; 340 } 341 342 } 343 344 final class PlayerNeedChunkEvent : PlayerEvent, Cancellable { 345 346 mixin Cancellable.Implementation; 347 348 mixin PlayerEvent.Implementation; 349 350 private ChunkPosition n_chunk; 351 352 public @safe @nogc this(Player player, ChunkPosition chunk) { 353 this.n_player = player; 354 this.n_chunk = chunk; 355 } 356 357 public @property @safe @nogc ChunkPosition chunk() { 358 return this.n_chunk; 359 } 360 361 } 362 363 final class PlayerRequestMapEvent : PlayerEvent, Cancellable { 364 365 mixin Cancellable.Implementation; 366 367 mixin PlayerEvent.Implementation; 368 369 public immutable ushort mapId; 370 371 public @safe @nogc this(Player player, ushort mapId) { 372 this.n_player = player; 373 this.mapId = mapId; 374 } 375 376 } 377 378 final class PlayerAfterSpawnEvent : PlayerEvent { 379 380 mixin PlayerEvent.Implementation; 381 382 public @safe @nogc this(Player player) { 383 this.n_player = player; 384 } 385 386 } 387 388 final class PlayerAfterDespawnEvent : PlayerEvent { 389 390 mixin PlayerEvent.Implementation; 391 392 public @safe @nogc this(Player player) { 393 this.n_player = player; 394 } 395 396 } 397 398 final class PlayerBreakBlockEvent : PlayerEvent, Cancellable { 399 400 mixin Cancellable.Implementation; 401 402 mixin PlayerEvent.Implementation; 403 404 private Block n_block; 405 private BlockPosition n_position; 406 public bool drop = true; 407 public bool consumeItem = true; 408 public bool removeBlock = true; 409 public bool particles = true; 410 411 public @safe @nogc this(Player player, Block block, BlockPosition position) { 412 this.n_player = player; 413 this.n_block = block; 414 this.n_position = position; 415 } 416 417 public @property @safe @nogc Block block() { 418 return this.n_block; 419 } 420 421 public @property @safe @nogc BlockPosition position() { 422 return this.n_position; 423 } 424 425 } 426 427 final class PlayerPlaceBlockEvent : PlayerEvent, Cancellable { 428 429 mixin Cancellable.Implementation; 430 431 mixin PlayerEvent.Implementation; 432 433 private BlockPosition n_position; 434 private Slot n_slot; 435 public immutable uint face; 436 437 public @safe @nogc this(Player player, Slot slot, BlockPosition position, uint face) { 438 this.n_player = player; 439 this.n_slot = slot; 440 this.n_position = position; 441 this.face = face; 442 } 443 444 public @property @safe @nogc Slot slot() { 445 return this.n_slot; 446 } 447 448 public @property @safe @nogc Item item() { 449 return this.n_slot.item; 450 } 451 452 public @property @safe @nogc BlockPosition position() { 453 return this.n_position; 454 } 455 456 } 457 458 /*class PlayerPickupEntityEvent : PlayerCancellableEvent { 459 460 private Entity n_entity; 461 462 public @safe @nogc this(Player player, Entity entity) { 463 super(player); 464 this.n_entity = entity; 465 } 466 467 public final @property @safe @nogc Entity entity() { 468 return this.n_entity; 469 } 470 471 } 472 473 final class PlayerPickupItemEvent : PlayerPickupEntityEvent { 474 475 private Slot n_slot; 476 477 public @safe @nogc this(Player player, ItemEntity item) { 478 super(player, item); 479 this.n_slot = item.slot; 480 } 481 482 public @property @safe @nogc Slot slot() { 483 return this.n_slot; 484 } 485 486 public @property @safe @nogc Item item() { 487 return this.n_slot.item; 488 } 489 490 }*/ 491 492 final class PlayerDropItemEvent : PlayerEvent, Cancellable { 493 494 mixin Cancellable.Implementation; 495 496 mixin PlayerEvent.Implementation; 497 498 private Slot n_slot; 499 500 public @safe @nogc this(Player player, Slot slot) { 501 this.n_player = player; 502 this.n_slot = slot; 503 } 504 505 public @property @safe @nogc Slot slot() { 506 return this.n_slot; 507 } 508 509 }