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