Advertisement
Guest User

Untitled

a guest
Dec 30th, 2015
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 13.16 KB | None | 0 0
  1. module world.FallblockWorld;
  2.  
  3. import std.algorithm : max, min;
  4. import std.conv : to;
  5. import std.random : uniform;
  6.  
  7. import Player;
  8. import Server;
  9. import block.Block;
  10. import entity.BlockEntity;
  11. import event.world.player.PlayerChatEvent;
  12. import event.world.player.PlayerLeftEvent;
  13. import event.world.player.PlayerMoveEvent;
  14. import event.world.player.PlayerSpawnEvent;
  15. import network.packet.mcpe.UpdateAttributesPacket;
  16. import network.packet.mcpe.UpdateBlockPacket;
  17. import network.packet.misc.BatchPacket;
  18. import util.Attribute;
  19. import util.Gamemode;
  20. import util.Text;
  21. import util.Util : milliseconds;
  22. import util.math.Vector2;
  23. import util.math.Vector3;
  24. import world.Chunk;
  25. import world.World;
  26. import world.generation.SpleefGenerator;
  27.  
  28. class FallblockWorld : World {
  29.  
  30.     private static immutable uint RADIUS = 18;
  31.     private static immutable ubyte HEIGHT = 10;
  32.  
  33.     private static immutable uint LOBBY = 52;
  34.     private static immutable uint BASE_TIME = 60; //in ticks
  35.     private static immutable uint PER_LEVEL = 10;
  36.     private static immutable uint RESTORE = 180;
  37.     private static immutable uint RESTORE_COOLDOWN = 10;
  38.  
  39.     private static immutable string TASK_LOBBY = "lobby";
  40.     private static immutable string TASK_GAME = "game";
  41.  
  42.     private static immutable ubyte MAX_LEVEL = 13;
  43.  
  44.     private static immutable ubyte RUNNING = 0;
  45.     private static immutable ubyte FALLING = 1;
  46.  
  47.     private static ubyte MIN_PLAYERS = 2;
  48.  
  49.     private Chunk[] def;
  50.  
  51.     private uint counter;
  52.     private bool started;
  53.  
  54.     private ubyte level;
  55.     private ubyte status;
  56.  
  57.     private Player[string] gamers;
  58.     private BlockEntity[string] over;
  59.  
  60.     private Vector2[][ubyte] mapped;
  61.  
  62.     public this(string name, Server server) {
  63.         super(name, server, new SpleefGenerator(RADIUS));
  64.         this.spawn = new Vector3(0, HEIGHT+1, 0);
  65.         this.gamemode.immutableWorld = true;
  66.         this.gamemode.pvp = false;
  67.         this.gamemode.pvm = false;
  68.         this.gamemode.staticTime = true;
  69.         int start = -((RADIUS+1)/16)-2;
  70.         int end = (RADIUS+1)/16+2;
  71.         foreach(int x ; start..end) {
  72.             foreach(int z ; start..end) {
  73.                 this.generateChunk(x, z);
  74.                 this.def ~= this.getChunk(x, z);
  75.             }
  76.         }
  77.         super.addTask("announce", &this.announceTask, 584);
  78.         this.lobby(true, true);
  79.     }
  80.  
  81.     public override Chunk[] getDefaultChunks() {
  82.         return this.def;
  83.     }
  84.  
  85.     private void announceTask(ulong tick, ulong repeat) {
  86.         //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");
  87.     }
  88.  
  89.     private void lobby(bool reset=true, bool first=false) {
  90.         //reset the tasks
  91.         super.removeTask(TASK_GAME);
  92.         super.addTask(TASK_LOBBY, &this.lobbyTask, 20);
  93.         //send the default blocks to everyone
  94.         if(reset) {
  95.             Block block = new Block(BlockId.STAINED_CLAY, BlockMeta.WHITE);
  96.             Block up = new Block(BlockId.INVISIBLE_BEDROCK);
  97.             foreach(Vector2 vector ; to!SpleefGenerator(this.generator).getGround()) {
  98.                 super.setBlock(block, to!int(vector.getX()), HEIGHT, to!int(vector.getZ())); //TODO inviare i chunk nuovi al posto dei blocchi (?)
  99.                 /*if(first) */super.setBlock(up, to!int(vector.getX()), HEIGHT+4, to!int(vector.getZ()));
  100.             }
  101.             //reset the gamers list
  102.             foreach(string s, Player player; this.gamers) {
  103.                 this.gamers.remove(s);
  104.                 if(player.getUsername() in this.over) {
  105.                     player.hideEntity(this.over[player.getUsername()]);
  106.                     this.over.remove(player.getUsername());
  107.                 }
  108.             }
  109.             foreach(Player player ; super.getPlayers()) {
  110.                 this.gamers[player.getUsername()] = player;
  111.                 player.setPosition(this.spawn);
  112.                 player.sendPosition();
  113.                 this.setPlayerStatus(player);
  114.             }
  115.             //remove the blocks
  116.             foreach(string name, BlockEntity be; this.over) {
  117.                 foreach(Player player ; super.getPlayers()) {
  118.                     player.hideEntity(be);
  119.                 }
  120.                 this.over.remove(name);
  121.             }
  122.         }
  123.         this.updateTimer(true);
  124.         this.updateAfterfallTimer(true);
  125.         //update the status
  126.         this.counter = LOBBY;
  127.         this.started = false;
  128.     }
  129.  
  130.     private void game() {
  131.         //check the players count
  132.         if(this.gamers.length < MIN_PLAYERS) {
  133.             super.broadcast("At least " ~ Text.GREY ~ to!string(MIN_PLAYERS) ~ Text.WHITE ~ " players needed. Restarting the countdown...");
  134.             this.lobby(false);
  135.             return;
  136.         } else {
  137.             super.broadcast(Text.GREEN ~ "The game is started");
  138.         }
  139.         //update the tasks
  140.         super.removeTask(TASK_LOBBY);
  141.         super.addTask(TASK_GAME, &this.gameTask, 1);
  142.         //add the players
  143.         foreach(Player player ; super.getPlayers()) {
  144.             this.gamers[player.getUsername()] = player;
  145.             player.setPosition(this.spawn);
  146.             player.sendPosition();
  147.         }
  148.         //set the status
  149.         this.started = true;
  150.         this.level = 1;
  151.         this.status = RUNNING;
  152.         this.prepareLevel(this.level);
  153.         this.updatePlayersCount();
  154.     }
  155.  
  156.     private void end() {
  157.         //reset the chat colors
  158.         foreach(Player player ; super.getPlayers()) {
  159.             player.var["color"] = Text.GREY;
  160.         }
  161.         //called when the time expires or only 1 player left on the platform
  162.         string pls[];
  163.         foreach(Player player ; this.gamers) {
  164.             pls ~= player.getUsername();
  165.             player.var["color"] = Text.GREEN;
  166.         }
  167.         string winners = "";
  168.         if(pls.length == 1) winners = pls[0];
  169.         else if(pls.length >= 2) {
  170.             winners = pls[$-2] ~ " and " ~ pls[$-1];
  171.             foreach(size_t i ; 0..pls.length-2) {
  172.                 winners = pls[i] ~ ", " ~ winners;
  173.             }
  174.         }
  175.         super.broadcast(Text.GREEN ~ (winners.length == 0 ? "Nobody won this game" : winners ~ " won the game"));
  176.         this.lobby();
  177.     }
  178.  
  179.     private void lobbyTask(ulong tick, ulong repeat) {
  180.         this.counter--;
  181.         if(this.counter == 0) {
  182.             this.game();
  183.         } else if(this.counter <= 5 || this.counter % 10 == 0) {
  184.             super.broadcast(Text.WHITE ~ "The game will start in " ~ Text.GREY ~ to!string(this.counter) ~ " " ~ Text.WHITE ~ (this.counter == 1 ? "second" : "seconds"));
  185.         }
  186.     }
  187.  
  188.     private void gameTask(ulong tick, ulong repeat) {
  189.         if(--this.counter == 0) {
  190.             if(this.status == RUNNING) {
  191.                 this.fall();
  192.             } else {
  193.                 //next level or end
  194.                 if(++this.level <= MAX_LEVEL) {
  195.                     this.prepareLevel(this.level);
  196.                 } else {
  197.                     this.end();
  198.                 }
  199.             }
  200.         } else if(this.status == RUNNING) {
  201.             this.updateTimer();
  202.         } else {
  203.             this.updateAfterfallTimer();
  204.         }
  205.     }
  206.  
  207.     private void prepareLevel(ubyte level) {
  208.         //set the status
  209.         this.status = RUNNING;
  210.         this.counter = this.getLevelTime(level);
  211.         //draw this level blocks
  212.         ubyte[] blocks;
  213.         for(uint c=0; c<level+1; c++) {
  214.             ubyte block = to!ubyte(uniform(0, 16));
  215.             bool add = true;
  216.             foreach(ubyte bl ; blocks) {
  217.                 if(bl == block) {
  218.                     add = false;
  219.                     break;
  220.                 }
  221.             }
  222.             if(add) blocks ~= block;
  223.             else c--;
  224.         }
  225.         //set the blocks for the players and teleport
  226.         foreach(Player player ; this.gamers) {
  227.             //get his colour
  228.             ubyte block = blocks[uniform(0, $)];
  229.             player.var["block"] = to!string(block);
  230.             //add and spawn the block
  231.             BlockEntity entity = new BlockEntity(BlockId.STAINED_CLAY, block);
  232.             entity.setPosition(new Vector3(player.getX(), HEIGHT+5.5, player.getZ()));
  233.             player.showEntity(entity);
  234.             this.over[player.getUsername()] = entity;
  235.             //also spawn to the spectators
  236.             foreach(Player spec ; super.getPlayers()) {
  237.                 if(spec.getUsername() !in this.gamers) {
  238.                     spec.showEntity(entity);
  239.                 }
  240.             }
  241.         }
  242.         //generate the new terrain
  243.         foreach(ubyte block, Vector2[] array; this.mapped) {
  244.             this.mapped.remove(block);
  245.         }
  246.         foreach(Vector2 vector ; to!SpleefGenerator(this.generator).getGround()) {
  247.             ubyte block = blocks[uniform(0, $)];
  248.             this.setBlock(new Block(BlockId.STAINED_CLAY, block), to!int(vector.getX()), HEIGHT, to!int(vector.getZ()));
  249.             this.mapped[block] ~= vector;
  250.         }
  251.     }
  252.  
  253.     private void fall() {
  254.         //set the status
  255.         this.status = FALLING;
  256.         this.counter = this.getFallTime(this.level);
  257.         //remove blocks and the entities
  258.         foreach(Player player ; this.gamers) {
  259.             this.removeOver(player);
  260.             //send the new blocks
  261.             ubyte block = to!ubyte(player.var["block"]);
  262.             BlockUpdate[][string] send;
  263.             foreach(ubyte blocks, Vector2[] vectors; this.mapped) {
  264.                 if(blocks != block) {
  265.                     foreach(Vector2 vector ; this.mapped[blocks]) {
  266.                         BlockUpdate b = BlockUpdate(to!int(vector.getX()), HEIGHT, to!int(vector.getZ()), 0, 0, UpdateFlag.ALL_PRIORITY);
  267.                         send[to!string(b.x >> 4) ~ ":" ~ to!string(b.z >> 4)] ~= b;
  268.                     }
  269.                 }
  270.             }
  271.             foreach(BlockUpdate[] update ; send) {
  272.                 UpdateBlockPacket packet = new UpdateBlockPacket(update);
  273.                 packet.encode();
  274.                 if(packet.getBuffer().length > 1000) {
  275.                     new Thread({
  276.                             //big packets for big changes
  277.                             BatchPacket batch = new BatchPacket(packet.getBuffer(), false);
  278.                             batch.encode();
  279.                             player.sendPacket(batch);
  280.                         }).start();
  281.                 } else {
  282.                     player.sendPacket(packet);
  283.                 }
  284.             }
  285.         }
  286.         //remove all the block entities
  287.         foreach(string name, BlockEntity be; this.over) {
  288.             this.over.remove(name);
  289.         }
  290.     }
  291.  
  292.     private void playerDie(Player player, bool exit=false) {
  293.         if(player.getUsername() in this.gamers) {
  294.             this.gamers.remove(player.getUsername());
  295.             if(this.started) {
  296.                 super.broadcast(Text.GREY ~ player.getUsername() ~ Text.WHITE ~ " fell out of the arena");
  297.                 if(this.gamers.length <= 1) {
  298.                     this.end();
  299.                 } else {
  300.                     if(!exit) {
  301.                         this.removeOver(player);
  302.                         this.setSpectatorStatus(player);
  303.                     }
  304.                 }
  305.             }
  306.             this.updatePlayersCount();
  307.         }
  308.     }
  309.  
  310.     private void removeOver(Player player) {
  311.         //remove the block entity over a player
  312.         if(player.getUsername() in this.over) {
  313.             foreach(Player p ; super.getPlayers()) {
  314.                 p.hideEntity(this.over[player.getUsername()]);
  315.             }
  316.             this.over.remove(player.getUsername());
  317.         }
  318.     }
  319.  
  320.     private void updatePlayersCount() {
  321.         //sends the alive players count to the players
  322.         super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE_LEVEL, this.gamers.length)));
  323.     }
  324.  
  325.     private void updateTimer(bool full=false) {
  326.         //update the timer
  327.         super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE, full ? Attribute.DEFAULT : to!float(this.counter) / this.getLevelTime(this.level))));
  328.     }
  329.  
  330.     private void updateAfterfallTimer(bool full=false) {
  331.         //update the time before the new level
  332.         super.broadcast(new UpdateAttributesPacket(new Attribute(Attribute.EXPERIENCE, full ? Attribute.DEFAULT : to!float(this.getFallTime(this.level) - this.counter) / this.getFallTime(this.level))));
  333.     }
  334.  
  335.     private uint getLevelTime(uint level) {
  336.         return BASE_TIME + PER_LEVEL * (MAX_LEVEL - this.level + 1);
  337.     }
  338.  
  339.     private uint getFallTime(uint level) {
  340.         return RESTORE - RESTORE_COOLDOWN * (this.level - 1);
  341.     }
  342.  
  343.     private void setPlayerStatus(Player player) {
  344.         //set player as a gamer
  345.         Gamemode gm = player.getGamemode();
  346.         gm.allowFly = false;
  347.         gm.noClip = false;
  348.         player.sendSettings();
  349.         player.setGamemode(Gamemode.CREATIVE);
  350.         player.setGamemode(Gamemode.SURVIVAL);
  351.         player.setGamemode(Gamemode.SURVIVAL);
  352.         foreach(Player p ; this.getPlayers()) {
  353.             p.showPlayer(player);
  354.         }
  355.     }
  356.  
  357.     private void setSpectatorStatus(Player player) {
  358.         //set player as spectator
  359.         Gamemode gm = player.getGamemode();
  360.         gm.noClip = true;
  361.         gm.allowFly = true;
  362.         player.setGamemode(gm);
  363.         player.sendSettings();
  364.         foreach(Player p ; super.getPlayers()) {
  365.             p.hidePlayer(player);
  366.         }
  367.     }
  368.  
  369.     public override void onPlayerMove(PlayerMoveEvent event) {
  370.         if(this.started && this.status == RUNNING && event.getPlayer().getUsername() in this.gamers) {
  371.             //move his entity
  372.             this.over[event.getPlayer().getUsername()].setPosition(new Vector3(event.x, HEIGHT+5.5, event.z));
  373.             //event.getPlayer().sendEntitiesMovements([this.over[event.getPlayer().getUsername()]]);
  374.             //send the movements to all (is spawned only to the spectators and the player)
  375.             foreach(Player player ; super.getPlayers()) {
  376.                 player.sendEntitiesMovements([this.over[event.getPlayer().getUsername()]]);
  377.             }
  378.         }
  379.         if(event.y < HEIGHT-2) {
  380.             event.getPlayer().setPosition(this.spawn);
  381.             event.getPlayer().sendPosition();
  382.             event.y = HEIGHT;
  383.             if(this.started) {
  384.                 this.playerDie(event.getPlayer());
  385.             }
  386.         }
  387.         super.onPlayerMove(event);
  388.     }
  389.  
  390.     public override void onPlayerSpawn(PlayerSpawnEvent event) {
  391.         event.message = "";
  392.         if(!this.started) {
  393.             this.gamers[event.getPlayer().getUsername()] = event.getPlayer();
  394.         } else {
  395.             event.spawn = false;
  396.             this.setSpectatorStatus(event.getPlayer());
  397.             foreach(Player player ; this.gamers) {
  398.                 event.getPlayer().showPlayer(player);
  399.             }
  400.         }
  401.         super.onPlayerSpawn(event);
  402.         this.updatePlayersCount();
  403.     }
  404.  
  405.     public override void onPlayerLeft(PlayerLeftEvent event) {
  406.         event.message = "";
  407.         super.onPlayerLeft(event);
  408.         if(event.getPlayer().getUsername() in this.gamers) {
  409.             this.playerDie(event.getPlayer(), true);
  410.         }
  411.     }
  412.  
  413.     public override void onPlayerChat(PlayerChatEvent event) {
  414.         //just for and anti-spam
  415.         if("spam" in event.getPlayer().var) {
  416.             if(milliseconds() - to!ulong(event.getPlayer().var["spam"]) < 2500) {
  417.                 event.getPlayer().sendMessage(Text.RED ~ "Please slow down");
  418.                 return;
  419.             }
  420.         }
  421.         event.format = ("color" in event.getPlayer().var ? event.getPlayer().var["color"] : Text.GREY) ~ "{player}" ~ Text.WHITE ~ ": {message}";
  422.         super.onPlayerChat(event);
  423.         event.getPlayer().var["spam"] = to!string(milliseconds());
  424.     }
  425.  
  426. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement