Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module world.FallblockWorld;
- import std.algorithm : max, min;
- import std.conv : to;
- import std.random : uniform;
- import Player;
- import Server;
- import block.Block;
- import entity.BlockEntity;
- import event.world.player.PlayerChatEvent;
- import event.world.player.PlayerLeftEvent;
- import event.world.player.PlayerMoveEvent;
- import event.world.player.PlayerSpawnEvent;
- import network.packet.mcpe.UpdateAttributesPacket;
- import network.packet.mcpe.UpdateBlockPacket;
- import network.packet.misc.BatchPacket;
- import util.Attribute;
- import util.Gamemode;
- import util.Text;
- import util.Util : milliseconds;
- import util.math.Vector2;
- import util.math.Vector3;
- import world.Chunk;
- import world.World;
- import world.generation.SpleefGenerator;
- class FallblockWorld : World {
- private static immutable uint RADIUS = 18;
- private static immutable ubyte HEIGHT = 10;
- private static immutable uint LOBBY = 52;
- private static immutable uint BASE_TIME = 60; //in ticks
- private static immutable uint PER_LEVEL = 10;
- private static immutable uint RESTORE = 180;
- private static immutable uint RESTORE_COOLDOWN = 10;
- private static immutable string TASK_LOBBY = "lobby";
- private static immutable string TASK_GAME = "game";
- private static immutable ubyte MAX_LEVEL = 13;
- private static immutable ubyte RUNNING = 0;
- private static immutable ubyte FALLING = 1;
- private static ubyte MIN_PLAYERS = 2;
- private Chunk[] def;
- private uint counter;
- private bool started;
- private ubyte level;
- private ubyte status;
- private Player[string] gamers;
- private BlockEntity[string] over;
- private Vector2[][ubyte] mapped;
- public this(string name, Server server) {
- super(name, server, new SpleefGenerator(RADIUS));
- this.spawn = new Vector3(0, HEIGHT+1, 0);
- this.gamemode.immutableWorld = true;
- this.gamemode.pvp = false;
- this.gamemode.pvm = false;
- this.gamemode.staticTime = true;
- int start = -((RADIUS+1)/16)-2;
- int end = (RADIUS+1)/16+2;
- foreach(int x ; start..end) {
- foreach(int z ; start..end) {
- this.generateChunk(x, z);
- this.def ~= this.getChunk(x, z);
- }
- }
- super.addTask("announce", &this.announceTask, 584);
- this.lobby(true, true);
- }
- public override Chunk[] getDefaultChunks() {
- return this.def;
- }
- private void announceTask(ulong tick, ulong repeat) {
- //super.broadcast(Text.ITALIC ~ Text.AQUA ~ "This is a server test running " ~ Text.BOLD ~ "7SEL-PM" ~ Text.RESET ~ Text.AQUA ~ Text.ITALIC ~ " by " ~ Text.BLUE ~ "@kripto04");
- }
- private void lobby(bool reset=true, bool first=false) {
- //reset the tasks
- super.removeTask(TASK_GAME);
- super.addTask(TASK_LOBBY, &this.lobbyTask, 20);
- //send the default blocks to everyone
- if(reset) {
- Block block = new Block(BlockId.STAINED_CLAY, BlockMeta.WHITE);
- Block up = new Block(BlockId.INVISIBLE_BEDROCK);
- foreach(Vector2 vector ; to!SpleefGenerator(this.generator).getGround()) {
- super.setBlock(block, to!int(vector.getX()), HEIGHT, to!int(vector.getZ())); //TODO inviare i chunk nuovi al posto dei blocchi (?)
- /*if(first) */super.setBlock(up, to!int(vector.getX()), HEIGHT+4, to!int(vector.getZ()));
- }
- //reset the gamers list
- foreach(string s, Player player; this.gamers) {
- this.gamers.remove(s);
- if(player.getUsername() in this.over) {
- player.hideEntity(this.over[player.getUsername()]);
- this.over.remove(player.getUsername());
- }
- }
- foreach(Player player ; super.getPlayers()) {
- this.gamers[player.getUsername()] = player;
- player.setPosition(this.spawn);
- player.sendPosition();
- this.setPlayerStatus(player);
- }
- //remove the blocks
- foreach(string name, BlockEntity be; this.over) {
- foreach(Player player ; super.getPlayers()) {
- player.hideEntity(be);
- }
- this.over.remove(name);
- }
- }
- this.updateTimer(true);
- this.updateAfterfallTimer(true);
- //update the status
- this.counter = LOBBY;
- this.started = false;
- }
- private void game() {
- //check the players count
- if(this.gamers.length < MIN_PLAYERS) {
- super.broadcast("At least " ~ Text.GREY ~ to!string(MIN_PLAYERS) ~ Text.WHITE ~ " players needed. Restarting the countdown...");
- this.lobby(false);
- return;
- } else {
- super.broadcast(Text.GREEN ~ "The game is started");
- }
- //update the tasks
- super.removeTask(TASK_LOBBY);
- super.addTask(TASK_GAME, &this.gameTask, 1);
- //add the players
- foreach(Player player ; super.getPlayers()) {
- this.gamers[player.getUsername()] = player;
- player.setPosition(this.spawn);
- player.sendPosition();
- }
- //set the status
- this.started = true;
- this.level = 1;
- this.status = RUNNING;
- this.prepareLevel(this.level);
- this.updatePlayersCount();
- }
- private void end() {
- //reset the chat colors
- foreach(Player player ; super.getPlayers()) {
- player.var["color"] = Text.GREY;
- }
- //called when the time expires or only 1 player left on the platform
- string pls[];
- foreach(Player player ; this.gamers) {
- pls ~= player.getUsername();
- player.var["color"] = Text.GREEN;
- }
- string winners = "";
- if(pls.length == 1) winners = pls[0];
- else if(pls.length >= 2) {
- winners = pls[$-2] ~ " and " ~ pls[$-1];
- foreach(size_t i ; 0..pls.length-2) {
- winners = pls[i] ~ ", " ~ winners;
- }
- }
- super.broadcast(Text.GREEN ~ (winners.length == 0 ? "Nobody won this game" : winners ~ " won the game"));
- this.lobby();
- }
- private void lobbyTask(ulong tick, ulong repeat) {
- this.counter--;
- if(this.counter == 0) {
- this.game();
- } else if(this.counter <= 5 || this.counter % 10 == 0) {
- super.broadcast(Text.WHITE ~ "The game will start in " ~ Text.GREY ~ to!string(this.counter) ~ " " ~ Text.WHITE ~ (this.counter == 1 ? "second" : "seconds"));
- }
- }
- private void gameTask(ulong tick, ulong repeat) {
- if(--this.counter == 0) {
- if(this.status == RUNNING) {
- this.fall();
- } else {
- //next level or end
- if(++this.level <= MAX_LEVEL) {
- this.prepareLevel(this.level);
- } else {
- this.end();
- }
- }
- } else if(this.status == RUNNING) {
- this.updateTimer();
- } else {
- this.updateAfterfallTimer();
- }
- }
- private void prepareLevel(ubyte level) {
- //set the status
- this.status = RUNNING;
- this.counter = this.getLevelTime(level);
- //draw this level blocks
- ubyte[] blocks;
- for(uint c=0; c<level+1; c++) {
- ubyte block = to!ubyte(uniform(0, 16));
- bool add = true;
- foreach(ubyte bl ; blocks) {
- if(bl == block) {
- add = false;
- break;
- }
- }
- if(add) blocks ~= block;
- else c--;
- }
- //set the blocks for the players and teleport
- foreach(Player player ; this.gamers) {
- //get his colour
- ubyte block = blocks[uniform(0, $)];
- player.var["block"] = to!string(block);
- //add and spawn the block
- BlockEntity entity = new BlockEntity(BlockId.STAINED_CLAY, block);
- entity.setPosition(new Vector3(player.getX(), HEIGHT+5.5, player.getZ()));
- player.showEntity(entity);
- this.over[player.getUsername()] = entity;
- //also spawn to the spectators
- foreach(Player spec ; super.getPlayers()) {
- if(spec.getUsername() !in this.gamers) {
- spec.showEntity(entity);
- }
- }
- }
- //generate the new terrain
- foreach(ubyte block, Vector2[] array; this.mapped) {
- this.mapped.remove(block);
- }
- foreach(Vector2 vector ; to!SpleefGenerator(this.generator).getGround()) {
- ubyte block = blocks[uniform(0, $)];
- this.setBlock(new Block(BlockId.STAINED_CLAY, block), to!int(vector.getX()), HEIGHT, to!int(vector.getZ()));
- this.mapped[block] ~= vector;
- }
- }
- private void fall() {
- //set the status
- this.status = FALLING;
- this.counter = this.getFallTime(this.level);
- //remove blocks and the entities
- foreach(Player player ; this.gamers) {
- this.removeOver(player);
- //send the new blocks
- ubyte block = to!ubyte(player.var["block"]);
- BlockUpdate[][string] send;
- foreach(ubyte blocks, Vector2[] vectors; this.mapped) {
- if(blocks != block) {
- foreach(Vector2 vector ; this.mapped[blocks]) {
- BlockUpdate b = BlockUpdate(to!int(vector.getX()), HEIGHT, to!int(vector.getZ()), 0, 0, UpdateFlag.ALL_PRIORITY);
- send[to!string(b.x >> 4) ~ ":" ~ to!string(b.z >> 4)] ~= b;
- }
- }
- }
- foreach(BlockUpdate[] update ; send) {
- UpdateBlockPacket packet = new UpdateBlockPacket(update);
- packet.encode();
- if(packet.getBuffer().length > 1000) {
- new Thread({
- //big packets for big changes
- BatchPacket batch = new BatchPacket(packet.getBuffer(), false);
- batch.encode();
- player.sendPacket(batch);
- }).start();
- } else {
- player.sendPacket(packet);
- }
- }
- }
- //remove all the block entities
- foreach(string name, BlockEntity be; this.over) {
- this.over.remove(name);
- }
- }
- private void playerDie(Player player, bool exit=false) {
- if(player.getUsername() in this.gamers) {
- this.gamers.remove(player.getUsername());
- if(this.started) {
- super.broadcast(Text.GREY ~ player.getUsername() ~ Text.WHITE ~ " fell out of the arena");
- if(this.gamers.length <= 1) {
- this.end();
- } else {
- if(!exit) {
- this.removeOver(player);
- this.setSpectatorStatus(player);
- }
- }
- }
- this.updatePlayersCount();
- }
- }
- private void removeOver(Player player) {
- //remove the block entity over a player
- if(player.getUsername() in this.over) {
- foreach(Player p ; super.getPlayers()) {
- p.hideEntity(this.over[player.getUsername()]);
- }
- this.over.remove(player.getUsername());
- }
- }
- private void updatePlayersCount() {
- //sends the alive players count to the players
- super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE_LEVEL, this.gamers.length)));
- }
- private void updateTimer(bool full=false) {
- //update the timer
- super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE, full ? Attribute.DEFAULT : to!float(this.counter) / this.getLevelTime(this.level))));
- }
- private void updateAfterfallTimer(bool full=false) {
- //update the time before the new level
- super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE, full ? Attribute.DEFAULT : to!float(this.getFallTime(this.level) - this.counter) / this.getFallTime(this.level))));
- }
- private uint getLevelTime(uint level) {
- return BASE_TIME + PER_LEVEL * (MAX_LEVEL - this.level + 1);
- }
- private uint getFallTime(uint level) {
- return RESTORE - RESTORE_COOLDOWN * (this.level - 1);
- }
- private void setPlayerStatus(Player player) {
- //set player as a gamer
- Gamemode gm = player.getGamemode();
- gm.allowFly = false;
- gm.noClip = false;
- player.sendSettings();
- player.setGamemode(Gamemode.CREATIVE);
- player.setGamemode(Gamemode.SURVIVAL);
- player.setGamemode(Gamemode.SURVIVAL);
- foreach(Player p ; this.getPlayers()) {
- p.showPlayer(player);
- }
- }
- private void setSpectatorStatus(Player player) {
- //set player as spectator
- Gamemode gm = player.getGamemode();
- gm.noClip = true;
- gm.allowFly = true;
- player.setGamemode(gm);
- player.sendSettings();
- foreach(Player p ; super.getPlayers()) {
- p.hidePlayer(player);
- }
- }
- public override void onPlayerMove(PlayerMoveEvent event) {
- if(this.started && this.status == RUNNING && event.getPlayer().getUsername() in this.gamers) {
- //move his entity
- this.over[event.getPlayer().getUsername()].setPosition(new Vector3(event.x, HEIGHT+5.5, event.z));
- //event.getPlayer().sendEntitiesMovements([this.over[event.getPlayer().getUsername()]]);
- //send the movements to all (is spawned only to the spectators and the player)
- foreach(Player player ; super.getPlayers()) {
- player.sendEntitiesMovements([this.over[event.getPlayer().getUsername()]]);
- }
- }
- if(event.y < HEIGHT-2) {
- event.getPlayer().setPosition(this.spawn);
- event.getPlayer().sendPosition();
- event.y = HEIGHT;
- if(this.started) {
- this.playerDie(event.getPlayer());
- }
- }
- super.onPlayerMove(event);
- }
- public override void onPlayerSpawn(PlayerSpawnEvent event) {
- event.message = "";
- if(!this.started) {
- this.gamers[event.getPlayer().getUsername()] = event.getPlayer();
- } else {
- event.spawn = false;
- this.setSpectatorStatus(event.getPlayer());
- foreach(Player player ; this.gamers) {
- event.getPlayer().showPlayer(player);
- }
- }
- super.onPlayerSpawn(event);
- this.updatePlayersCount();
- }
- public override void onPlayerLeft(PlayerLeftEvent event) {
- event.message = "";
- super.onPlayerLeft(event);
- if(event.getPlayer().getUsername() in this.gamers) {
- this.playerDie(event.getPlayer(), true);
- }
- }
- public override void onPlayerChat(PlayerChatEvent event) {
- //just for and anti-spam
- if("spam" in event.getPlayer().var) {
- if(milliseconds() - to!ulong(event.getPlayer().var["spam"]) < 2500) {
- event.getPlayer().sendMessage(Text.RED ~ "Please slow down");
- return;
- }
- }
- event.format = ("color" in event.getPlayer().var ? event.getPlayer().var["color"] : Text.GREY) ~ "{player}" ~ Text.WHITE ~ ": {message}";
- super.onPlayerChat(event);
- event.getPlayer().var["spam"] = to!string(milliseconds());
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement