mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-10-04 02:52:21 -04:00
1578 lines
73 KiB
C#
1578 lines
73 KiB
C#
/*
|
|
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
|
|
Dual-licensed under the Educational Community License, Version 2.0 and
|
|
the GNU General Public License, Version 3 (the "Licenses"); you may
|
|
not use this file except in compliance with the Licenses. You may
|
|
obtain a copy of the Licenses at
|
|
http://www.opensource.org/licenses/ecl2.php
|
|
http://www.gnu.org/licenses/gpl-3.0.html
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the Licenses are distributed on an "AS IS"
|
|
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
or implied. See the Licenses for the specific language governing
|
|
permissions and limitations under the Licenses.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using MCGalaxy.SQL;
|
|
|
|
namespace MCGalaxy {
|
|
|
|
public sealed partial class Player : IDisposable {
|
|
|
|
public void ManualChange(ushort x, ushort y, ushort z, byte action, byte type, byte extType = 0) {
|
|
byte b = level.GetTile(x, y, z);
|
|
if ( b == Block.Zero ) { return; }
|
|
if ( jailed || !agreed ) { RevertBlock(x, y, z); return; }
|
|
if ( level.IsMuseum && Blockchange == null ) {
|
|
return;
|
|
}
|
|
|
|
if ( !deleteMode ) {
|
|
string info = level.foundInfo(x, y, z);
|
|
if ( info.Contains("wait") ) return;
|
|
}
|
|
|
|
if ( !canBuild ) {
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if ( Server.verifyadmins && adminpen ) {
|
|
SendMessage("&cYou must use &a/pass [Password]&c to verify!");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if (Server.ZombieModeOn && Server.zombie.HandlesManualChange(this, x, y, z, action, type, b))
|
|
return;
|
|
|
|
if ( Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this) ) {
|
|
SendMessage("You are out of the round, and cannot build.");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
Level.BlockPos bP;
|
|
bP.name = name;
|
|
bP.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
|
|
bP.index = level.PosToInt(x, y, z);
|
|
bP.type = type;
|
|
bP.extType = extType;
|
|
|
|
lastClick[0] = x; lastClick[1] = y; lastClick[2] = z;
|
|
if ( Blockchange != null ) {
|
|
if ( Blockchange.Method.ToString().IndexOf("AboutBlockchange") == -1 && !level.IsMuseum ) {
|
|
bP.deleted = true;
|
|
level.blockCache.Add(bP);
|
|
}
|
|
|
|
Blockchange(this, x, y, z, type, extType);
|
|
return;
|
|
}
|
|
if ( PlayerBlockChange != null )
|
|
PlayerBlockChange(this, x, y, z, type, extType);
|
|
OnBlockChangeEvent.Call(this, x, y, z, type, extType);
|
|
if ( cancelBlock ) {
|
|
cancelBlock = false;
|
|
return;
|
|
}
|
|
|
|
if ( group.Permission == LevelPermission.Banned ) return;
|
|
if ( group.Permission == LevelPermission.Guest ) {
|
|
int Diff = Math.Abs((pos[0] / 32) - x) + Math.Abs((pos[1] / 32) - y)
|
|
+ Math.Abs((pos[2] / 32) - z);
|
|
|
|
if ((Diff > ReachDistance + 4) && lastCMD != "click") {
|
|
Server.s.Log(name + " attempted to build with a " + Diff + " distance offset");
|
|
SendMessage("You can't build that far away.");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
}
|
|
|
|
if (!Block.canPlace(this, b) && !Block.BuildIn(b) && !Block.AllowBreak(b)) {
|
|
SendMessage("Cannot build here!");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if (!Block.canPlace(this, type)) {
|
|
SendMessage("You can't place this block type!");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if (b >= 200 && b < 220) {
|
|
SendMessage("Block is active, you cant disturb it!");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if (action > 1 ) { Kick("Unknown block action!"); return; }
|
|
byte oldType = type;
|
|
if (type < 128) type = bindings[type];
|
|
|
|
//Ignores updating blocks that are the same and send block only to the player
|
|
byte newBlock = (painting || action == 1) ? type : (byte)0;
|
|
if (b == newBlock && (painting || oldType != type)) {
|
|
if (b != Block.custom_block || extType == level.GetExtTile(x, y, z)) {
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
}
|
|
//else
|
|
if ( !painting && action == 0 ) {
|
|
if ( !deleteMode ) {
|
|
if ( Block.portal(b) ) { HandlePortal(this, x, y, z, b); return; }
|
|
if ( Block.mb(b) ) { HandleMsgBlock(this, x, y, z, b); return; }
|
|
}
|
|
|
|
bP.deleted = true;
|
|
level.blockCache.Add(bP);
|
|
DeleteBlock(b, x, y, z, type, extType);
|
|
} else {
|
|
bP.deleted = false;
|
|
level.blockCache.Add(bP);
|
|
PlaceBlock(b, x, y, z, type, extType);
|
|
}
|
|
}
|
|
|
|
byte[] HandleMessage(byte[] buffer) {
|
|
try {
|
|
int length = 0; byte msg = buffer[0];
|
|
// Get the length of the message by checking the first byte
|
|
switch (msg) {
|
|
//For wom
|
|
case (byte)'G':
|
|
return new byte[1];
|
|
case Opcode.Handshake:
|
|
length = 130;
|
|
break;
|
|
case Opcode.SetBlockClient:
|
|
if (!loggedIn)
|
|
goto default;
|
|
length = 8;
|
|
break;
|
|
case Opcode.EntityTeleport:
|
|
if (!loggedIn)
|
|
goto default;
|
|
length = 9;
|
|
break;
|
|
case Opcode.Message:
|
|
if (!loggedIn)
|
|
goto default;
|
|
length = 65;
|
|
break;
|
|
case Opcode.CpeExtInfo:
|
|
length = 66;
|
|
break;
|
|
case Opcode.CpeExtEntry:
|
|
length = 68;
|
|
break;
|
|
case Opcode.CpeCustomBlockSupportLevel:
|
|
length = 1;
|
|
break;
|
|
default:
|
|
if (!dontmindme)
|
|
Kick("Unhandled message id \"" + msg + "\"!");
|
|
else
|
|
Server.s.Log(Encoding.UTF8.GetString(buffer, 0, buffer.Length));
|
|
return new byte[0];
|
|
}
|
|
if (buffer.Length > length) {
|
|
byte[] message = new byte[length];
|
|
Buffer.BlockCopy(buffer, 1, message, 0, length);
|
|
|
|
byte[] tempbuffer = new byte[buffer.Length - length - 1];
|
|
Buffer.BlockCopy(buffer, length + 1, tempbuffer, 0, buffer.Length - length - 1);
|
|
|
|
buffer = tempbuffer;
|
|
|
|
switch (msg) {
|
|
case Opcode.Handshake:
|
|
HandleLogin(message);
|
|
lock (pendingLock)
|
|
pendingNames.Remove(truename);
|
|
break;
|
|
case Opcode.SetBlockClient:
|
|
if (!loggedIn)
|
|
break;
|
|
HandleBlockchange(message);
|
|
break;
|
|
case Opcode.EntityTeleport:
|
|
if (!loggedIn)
|
|
break;
|
|
HandleMovement(message);
|
|
break;
|
|
case Opcode.Message:
|
|
if (!loggedIn)
|
|
break;
|
|
HandleChat(message);
|
|
break;
|
|
case Opcode.CpeExtInfo:
|
|
HandleExtInfo( message );
|
|
break;
|
|
case Opcode.CpeExtEntry:
|
|
HandleExtEntry( message );
|
|
break;
|
|
case Opcode.CpeCustomBlockSupportLevel:
|
|
HandleCustomBlockSupportLevel( message );
|
|
break;
|
|
}
|
|
//thread.Start((object)message);
|
|
if (buffer.Length > 0)
|
|
buffer = HandleMessage(buffer);
|
|
else
|
|
return new byte[0];
|
|
}
|
|
} catch (Exception e) {
|
|
Server.ErrorLog(e);
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
#region Login
|
|
|
|
void HandleLogin(byte[] message)
|
|
{
|
|
try
|
|
{
|
|
if (loggedIn) return;
|
|
|
|
byte version = message[0];
|
|
name = enc.GetString(message, 1, 64).Trim();
|
|
truename = name;
|
|
|
|
lock (pendingLock) {
|
|
pendingNames.Add(name);
|
|
int altsCount = 0;
|
|
foreach (string other in pendingNames) {
|
|
if (other == truename) altsCount++;
|
|
}
|
|
|
|
if (altsCount > 1) {
|
|
Kick("Already logged in!", true); return;
|
|
}
|
|
}
|
|
|
|
string verify = enc.GetString(message, 65, 32).Trim();
|
|
if (Server.verify)
|
|
{
|
|
if (verify == "--" || verify !=
|
|
BitConverter.ToString(md5.ComputeHash(enc.GetBytes(Server.salt + truename)))
|
|
.Replace("-", "").ToLower())
|
|
{
|
|
if (!IPInPrivateRange(ip))
|
|
{
|
|
Kick("Login failed! Try again.", true); return;
|
|
}
|
|
}
|
|
}
|
|
DisplayName = name;
|
|
SkinName = name;
|
|
name += "+";
|
|
byte type = message[129];
|
|
|
|
isDev = Server.Devs.ContainsInsensitive(name);
|
|
isMod = Server.Mods.ContainsInsensitive(name);
|
|
isGCMod = Server.GCmods.ContainsInsensitive(name);
|
|
verifiedName = Server.verify;
|
|
|
|
try {
|
|
Server.TempBan tBan = Server.tempBans.Find(tB => tB.name.ToLower() == name.ToLower());
|
|
if (tBan.allowedJoin < DateTime.Now) {
|
|
Server.tempBans.Remove(tBan);
|
|
} else {
|
|
Kick("You're still banned (temporary ban)!", true);
|
|
}
|
|
} catch { }
|
|
|
|
if (!CheckWhitelist()) return;
|
|
|
|
// ban check
|
|
if (Server.bannedIP.Contains(ip) && (!Server.useWhitelist || !onWhitelist)) {
|
|
Kick(Server.customBanMessage, true); return;
|
|
}
|
|
|
|
if (Group.findPlayerGroup(name) == Group.findPerm(LevelPermission.Banned)) {
|
|
if (!Server.useWhitelist || !onWhitelist) {
|
|
if (Ban.IsBanned(name)) {
|
|
string[] data = Ban.GetBanData(name);
|
|
Kick("Banned for \"" + data[1] + "\" by " + data[0], true);
|
|
} else {
|
|
Kick(Server.customBanMessage, true);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
//server maxplayer check
|
|
if (!VIP.Find(this))
|
|
{
|
|
// Check to see how many guests we have
|
|
if (PlayerInfo.players.Count >= Server.players && !IPInPrivateRange(ip)) { Kick("Server full!"); return; }
|
|
// Code for limiting no. of guests
|
|
if (Group.findPlayerGroup(name) == Group.findPerm(LevelPermission.Guest))
|
|
{
|
|
// Check to see how many guests we have
|
|
int currentNumOfGuests = PlayerInfo.players.Count(pl => pl.group.Permission <= LevelPermission.Guest);
|
|
if (currentNumOfGuests >= Server.maxGuests)
|
|
{
|
|
if (Server.guestLimitNotify) Chat.GlobalMessageOps("Guest " + this.DisplayName + " couldn't log in - too many guests.");
|
|
Server.s.Log("Guest " + this.name + " couldn't log in - too many guests.");
|
|
const string msg = "Server has reached max number of guests";
|
|
LeaveServer(msg, msg, true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (version != Server.version) { LeaveServer("Wrong version!", "Wrong version!", true); return; }
|
|
|
|
foreach (Player p in PlayerInfo.players) {
|
|
if (p.name == name) {
|
|
if (Server.verify) {
|
|
p.Kick("Someone logged in as you!"); break;
|
|
} else {
|
|
Kick("Already logged in!", true); return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LoadIgnores();
|
|
if (type == 0x42) {
|
|
hasCpe = true;
|
|
|
|
SendExtInfo(16);
|
|
SendExtEntry(CpeExt.ClickDistance, 1);
|
|
SendExtEntry(CpeExt.CustomBlocks, 1);
|
|
SendExtEntry(CpeExt.HeldBlock, 1);
|
|
|
|
SendExtEntry(CpeExt.TextHotkey, 1);
|
|
SendExtEntry(CpeExt.EnvColors, 1);
|
|
SendExtEntry(CpeExt.SelectionCuboid, 1);
|
|
|
|
SendExtEntry(CpeExt.BlockPermissions, 1);
|
|
SendExtEntry(CpeExt.ChangeModel, 1);
|
|
SendExtEntry(CpeExt.EnvMapAppearance, 2);
|
|
|
|
SendExtEntry(CpeExt.EnvWeatherType, 1);
|
|
SendExtEntry(CpeExt.HackControl, 1);
|
|
SendExtEntry(CpeExt.EmoteFix, 1);
|
|
|
|
SendExtEntry(CpeExt.FullCP437, 1);
|
|
SendExtEntry(CpeExt.LongerMessages, 1);
|
|
SendExtEntry(CpeExt.BlockDefinitions, 1);
|
|
|
|
SendExtEntry(CpeExt.BlockDefinitionsExt, 2);
|
|
}
|
|
|
|
try { left.Remove(name.ToLower()); }
|
|
catch { }
|
|
|
|
group = Group.findPlayerGroup(name);
|
|
Loading = true;
|
|
if (disconnected) return;
|
|
id = FreeId();
|
|
|
|
if (type != 0x42)
|
|
CompleteLoginProcess();
|
|
} catch (Exception e) {
|
|
Server.ErrorLog(e);
|
|
Player.GlobalMessage("An error occurred: " + e.Message);
|
|
}
|
|
}
|
|
|
|
bool CheckWhitelist() {
|
|
if (!Server.useWhitelist)
|
|
return true;
|
|
|
|
if (Server.verify) {
|
|
if (Server.whiteList.Contains(name))
|
|
onWhitelist = true;
|
|
} else {
|
|
// Verify Names is off. Gotta check the hard way.
|
|
Database.AddParams("@IP", ip);
|
|
DataTable ipQuery = Database.fillData("SELECT Name FROM Players WHERE IP = @IP");
|
|
|
|
if (ipQuery.Rows.Count > 0) {
|
|
if (ipQuery.Rows.Contains(name) && Server.whiteList.Contains(name)) {
|
|
onWhitelist = true;
|
|
}
|
|
}
|
|
ipQuery.Dispose();
|
|
}
|
|
if (!onWhitelist)
|
|
Kick("This is a private server!"); //i think someone forgot this?
|
|
return onWhitelist;
|
|
}
|
|
|
|
void CompleteLoginProcess() {
|
|
try {
|
|
SendMotd();
|
|
SendMap(null);
|
|
if (disconnected) return;
|
|
loggedIn = true;
|
|
|
|
lock (PlayerInfo.players)
|
|
PlayerInfo.players.Add(this);
|
|
|
|
connections.Remove(this);
|
|
|
|
Server.s.PlayerListUpdate();
|
|
|
|
//Test code to show when people come back with different accounts on the same IP
|
|
string alts = name + " is lately known as:";
|
|
bool found = false;
|
|
if (!ip.StartsWith("127.0.0.")) {
|
|
foreach (KeyValuePair<string, string> prev in left) {
|
|
if (prev.Value == ip)
|
|
{
|
|
found = true;
|
|
alts += " " + prev.Key;
|
|
}
|
|
}
|
|
if (found) {
|
|
if (group.Permission < Server.adminchatperm || !Server.adminsjoinsilent) {
|
|
Chat.GlobalMessageOps(alts);
|
|
//IRCBot.Say(temp, true); //Tells people in op channel on IRC
|
|
}
|
|
Server.s.Log(alts);
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
Server.ErrorLog(e);
|
|
Player.GlobalMessage("An error occurred: " + e.Message);
|
|
}
|
|
|
|
//OpenClassic Client Check
|
|
SendBlockchange(0, 0, 0, 0);
|
|
Database.AddParams("@Name", name);
|
|
DataTable playerDb = Database.fillData("SELECT * FROM Players WHERE Name=@Name");
|
|
|
|
if (playerDb.Rows.Count == 0)
|
|
InitPlayerStats(playerDb);
|
|
else
|
|
LoadPlayerStats(playerDb);
|
|
|
|
if (!Directory.Exists("players"))
|
|
Directory.CreateDirectory("players");
|
|
PlayerDB.Load(this);
|
|
SetPrefix();
|
|
playerDb.Dispose();
|
|
|
|
if (Server.server_owner != "" && Server.server_owner.ToLower().Equals(name.ToLower())) {
|
|
if (color == Group.standard.color) color = "&c";
|
|
if (title == "") title = "Owner";
|
|
SetPrefix();
|
|
}
|
|
|
|
if (Server.verifyadmins && group.Permission >= Server.verifyadminsrank)
|
|
adminpen = true;
|
|
if (emoteList.Contains(name)) parseSmiley = false;
|
|
if (!Directory.Exists("text/login"))
|
|
Directory.CreateDirectory("text/login");
|
|
if (!File.Exists("text/login/" + this.name + ".txt"))
|
|
CP437Writer.WriteAllText("text/login/" + this.name + ".txt", "joined the server.");
|
|
|
|
string joinm = "&a+ " + this.FullName + Server.DefaultColor + " " + File.ReadAllText("text/login/" + this.name + ".txt");
|
|
if (group.Permission < Server.adminchatperm || !Server.adminsjoinsilent) {
|
|
if ((Server.guestJoinNotify && group.Permission <= LevelPermission.Guest) || group.Permission > LevelPermission.Guest) {
|
|
PlayerInfo.players.ForEach(p1 => Player.SendMessage(p1, joinm));
|
|
}
|
|
}
|
|
if (group.Permission >= Server.adminchatperm && Server.adminsjoinsilent) {
|
|
hidden = true;
|
|
adminchat = true;
|
|
}
|
|
|
|
if (PlayerConnect != null)
|
|
PlayerConnect(this);
|
|
OnPlayerConnectEvent.Call(this);
|
|
|
|
CheckLoginJailed();
|
|
if (Server.agreetorulesonentry) {
|
|
if (!File.Exists("ranks/agreed.txt"))
|
|
File.WriteAllText("ranks/agreed.txt", "");
|
|
var agreedFile = File.ReadAllText("ranks/agreed.txt");
|
|
if (group.Permission == LevelPermission.Guest && !agreedFile.Contains(this.name.ToLower())) {
|
|
SendMessage("&9You must read the &c/rules&9 and &c/agree&9 to them before you can build and use commands!");
|
|
agreed = false;
|
|
}
|
|
}
|
|
|
|
if (Server.verifyadmins && group.Permission >= Server.verifyadminsrank) {
|
|
if (!Directory.Exists("extra/passwords") || !File.Exists("extra/passwords/" + this.name + ".dat"))
|
|
SendMessage("&cPlease set your admin verification password with &a/setpass [Password]!");
|
|
else
|
|
SendMessage("&cPlease complete admin verification with &a/pass [Password]!");
|
|
}
|
|
try
|
|
{
|
|
WaypointList.Load(this);
|
|
//if (Waypoints.Count > 0) { this.SendMessage("Loaded " + Waypoints.Count + " waypoints!"); }
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SendMessage("Error loading waypoints!");
|
|
Server.ErrorLog(ex);
|
|
}
|
|
try
|
|
{
|
|
if (File.Exists("ranks/muted.txt"))
|
|
{
|
|
using (StreamReader read = new StreamReader("ranks/muted.txt"))
|
|
{
|
|
string line;
|
|
while ((line = read.ReadLine()) != null)
|
|
{
|
|
if (line.ToLower() == this.name.ToLower())
|
|
{
|
|
this.muted = true;
|
|
Player.SendMessage(this, "!%cYou are still %8muted%c since your last login.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else { File.Create("ranks/muted.txt").Close(); }
|
|
}
|
|
catch { muted = false; }
|
|
|
|
Server.s.Log(name + " [" + ip + "] has joined the server.");
|
|
|
|
Server.zombie.PlayerJoinedServer(this);
|
|
try {
|
|
ushort x = (ushort)((0.5 + level.spawnx) * 32);
|
|
ushort y = (ushort)((1 + level.spawny) * 32);
|
|
ushort z = (ushort)((0.5 + level.spawnz) * 32);
|
|
pos = new ushort[3] { x, y, z }; rot = new byte[2] { level.rotx, level.roty };
|
|
|
|
GlobalSpawn(this, x, y, z, rot[0], rot[1], true);
|
|
foreach (Player p in PlayerInfo.players) {
|
|
if (p.level == level && p != this && !p.hidden)
|
|
SendSpawn(p.id, p.color + p.name, p.pos[0], p.pos[1], p.pos[2], p.rot[0], p.rot[1]);
|
|
if (HasCpeExt(CpeExt.ChangeModel))
|
|
SendChangeModel(p.id, p.model);
|
|
}
|
|
|
|
foreach (PlayerBot pB in PlayerBot.playerbots) {
|
|
if (pB.level == level)
|
|
SendSpawn(pB.id, pB.color + pB.name, pB.pos[0], pB.pos[1], pB.pos[2], pB.rot[0], pB.rot[1]);
|
|
}
|
|
} catch (Exception e) {
|
|
Server.ErrorLog(e);
|
|
Server.s.Log("Error spawning player \"" + name + "\"");
|
|
}
|
|
Loading = false;
|
|
}
|
|
|
|
void InitPlayerStats(DataTable playerDb) {
|
|
SendMessage("Welcome " + DisplayName + "! This is your first visit.");
|
|
PlayerInfo.CreateInfo(this);
|
|
}
|
|
|
|
void LoadPlayerStats(DataTable playerDb) {
|
|
PlayerInfo.LoadInfo(playerDb, this);
|
|
SendMessage("Welcome back " + color + prefix + DisplayName + "%S! " +
|
|
"You've been here " + totalLogins + " times!");
|
|
|
|
if (Server.muted.Contains(name)) {
|
|
muted = true;
|
|
GlobalMessage(DisplayName + " is still muted from the last time they went offline.");
|
|
}
|
|
}
|
|
|
|
void CheckLoginJailed() {
|
|
//very very sloppy, yes I know.. but works for the time
|
|
bool gotoJail = false;
|
|
string gotoJailMap = "", gotoJailName = "";
|
|
try {
|
|
if (File.Exists("ranks/jailed.txt"))
|
|
{
|
|
using (StreamReader read = new StreamReader("ranks/jailed.txt"))
|
|
{
|
|
string line;
|
|
while ((line = read.ReadLine()) != null)
|
|
{
|
|
string[] parts = line.Split();
|
|
if (parts[0].ToLower() == this.name.ToLower())
|
|
{
|
|
gotoJail = true;
|
|
gotoJailName = parts[0];
|
|
gotoJailMap = parts[1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
File.Create("ranks/jailed.txt").Close();
|
|
}
|
|
} catch {
|
|
gotoJail = false;
|
|
}
|
|
|
|
if (gotoJail) {
|
|
try {
|
|
Command.all.Find("goto").Use(this, gotoJailMap);
|
|
Command.all.Find("jail").Use(null, gotoJailName);
|
|
} catch (Exception e) {
|
|
Kick(e.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
void HandleBlockchange(byte[] message) {
|
|
try {
|
|
if ( !loggedIn ) return;
|
|
if ( CheckBlockSpam() ) return;
|
|
|
|
ushort x = NetUtils.ReadU16(message, 0);
|
|
ushort y = NetUtils.ReadU16(message, 2);
|
|
ushort z = NetUtils.ReadU16(message, 4);
|
|
byte action = message[6];
|
|
byte type = message[7];
|
|
byte extType = type;
|
|
|
|
if ((action == 0 || type == 0) && !level.Deletable) {
|
|
SendMessage("You cannot currently delete blocks in this level.");
|
|
RevertBlock(x, y, z); return;
|
|
} else if (action == 1 && !level.Buildable) {
|
|
SendMessage("You cannot currently place blocks in this level.");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
|
|
if (type >= Block.CpeCount) {
|
|
if (!HasCpeExt(CpeExt.BlockDefinitions) || level.CustomBlockDefs[type] == null) {
|
|
SendMessage("Invalid block type: " + type);
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
extType = type;
|
|
type = Block.custom_block;
|
|
}
|
|
ManualChange(x, y, z, action, type, extType);
|
|
} catch ( Exception e ) {
|
|
// Don't ya just love it when the server tattles?
|
|
Chat.GlobalMessageOps(DisplayName + " has triggered a block change error");
|
|
Chat.GlobalMessageOps(e.GetType().ToString() + ": " + e.Message);
|
|
Server.ErrorLog(e);
|
|
}
|
|
}
|
|
|
|
void HandlePortal(Player p, ushort x, ushort y, ushort z, byte b) {
|
|
try {
|
|
//safe against SQL injections because no user input is given here
|
|
DataTable Portals = Database.fillData("SELECT * FROM `Portals" + level.name + "` WHERE EntryX=" + (int)x + " AND EntryY=" + (int)y + " AND EntryZ=" + (int)z);
|
|
|
|
int LastPortal = Portals.Rows.Count - 1;
|
|
if ( LastPortal > -1 ) {
|
|
if ( level.name != Portals.Rows[LastPortal]["ExitMap"].ToString() ) {
|
|
if ( level.permissionvisit > this.group.Permission ) {
|
|
Player.SendMessage(this, "You do not have the adequate rank to visit this map!");
|
|
return;
|
|
}
|
|
ignorePermission = true;
|
|
Level thisLevel = level;
|
|
Command.all.Find("goto").Use(this, Portals.Rows[LastPortal]["ExitMap"].ToString());
|
|
if ( thisLevel == level ) { Player.SendMessage(p, "The map the portal goes to isn't loaded."); return; }
|
|
ignorePermission = false;
|
|
}
|
|
else SendBlockchange(x, y, z, b);
|
|
|
|
p.BlockUntilLoad(10);
|
|
Command.all.Find("move").Use(this, this.name + " " + Portals.Rows[LastPortal]["ExitX"].ToString() + " " + Portals.Rows[LastPortal]["ExitY"].ToString() + " " + Portals.Rows[LastPortal]["ExitZ"].ToString());
|
|
}
|
|
else {
|
|
Blockchange(this, x, y, z, Block.air, 0);
|
|
}
|
|
Portals.Dispose();
|
|
}
|
|
catch { Player.SendMessage(p, "Portal had no exit."); return; }
|
|
}
|
|
|
|
static char[] trimChars = { ' ' };
|
|
void HandleMsgBlock(Player p, ushort x, ushort y, ushort z, byte b) {
|
|
try {
|
|
//safe against SQL injections because no user input is given here
|
|
DataTable Messages = Database.fillData("SELECT * FROM `Messages" + level.name + "` WHERE X=" + (int)x + " AND Y=" + (int)y + " AND Z=" + (int)z);
|
|
|
|
int LastMsg = Messages.Rows.Count - 1;
|
|
if ( LastMsg > -1 ) {
|
|
string message = Messages.Rows[LastMsg]["Message"].ToString().Trim();
|
|
message = message.Replace("\\'", "\'");
|
|
if ( message != prevMsg || Server.repeatMessage ) {
|
|
if ( message.StartsWith("/") ) {
|
|
string[] parts = message.Remove(0, 1).Split(trimChars, 2);
|
|
HandleCommand(parts[0], parts.Length > 1 ? parts[1] : "");
|
|
} else {
|
|
Player.SendMessage(p, message);
|
|
}
|
|
prevMsg = message;
|
|
}
|
|
SendBlockchange(x, y, z, b);
|
|
} else {
|
|
Blockchange(this, x, y, z, Block.air, 0);
|
|
}
|
|
Messages.Dispose();
|
|
} catch {
|
|
Player.SendMessage(p, "No message was stored.");
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
}
|
|
|
|
void DeleteBlock(byte b, ushort x, ushort y, ushort z, byte type, byte extType) {
|
|
if ( deleteMode && b != Block.c4det ) { level.Blockchange(this, x, y, z, Block.air); return; }
|
|
|
|
if ( Block.tDoor(b) ) { RevertBlock(x, y, z); return; }
|
|
if ( Block.DoorAirs(b) != 0 ) {
|
|
if ( level.physics != 0 )
|
|
level.Blockchange(x, y, z, Block.DoorAirs(b));
|
|
else
|
|
RevertBlock(x, y, z);
|
|
return;
|
|
}
|
|
if ( Block.odoor(b) != Block.Zero ) {
|
|
if ( b == Block.odoor8 || b == Block.odoor8_air ) {
|
|
level.Blockchange(this, x, y, z, Block.odoor(b));
|
|
} else {
|
|
RevertBlock(x, y, z);
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch ( b ) {
|
|
case Block.door_tree__air: //Door_air
|
|
case Block.door_obsidian_air:
|
|
case Block.door_glass_air:
|
|
case Block.door_stone_air:
|
|
case Block.door_leaves_air:
|
|
case Block.door_sand_air:
|
|
case Block.door_wood_air:
|
|
case Block.door_green_air:
|
|
case Block.door_tnt_air:
|
|
case Block.door_stair_air:
|
|
case Block.door_iron_air:
|
|
case Block.door_gold_air:
|
|
case Block.door_cobblestone_air:
|
|
case Block.door_red_air:
|
|
case Block.door_darkpink_air:
|
|
case Block.door_darkgrey_air:
|
|
case Block.door_lightgrey_air:
|
|
case Block.door_white_air:
|
|
|
|
case Block.door_dirt_air:
|
|
case Block.door_grass_air:
|
|
case Block.door_blue_air:
|
|
case Block.door_book_air:
|
|
break;
|
|
case Block.rocketstart:
|
|
if ( level.physics < 2 || level.physics == 5 ) {
|
|
RevertBlock(x, y, z);
|
|
} else {
|
|
int newZ = 0, newX = 0, newY = 0;
|
|
|
|
SendBlockchange(x, y, z, Block.rocketstart);
|
|
if ( rot[0] < 48 || rot[0] > ( 256 - 48 ) )
|
|
newZ = -1;
|
|
else if ( rot[0] > ( 128 - 48 ) && rot[0] < ( 128 + 48 ) )
|
|
newZ = 1;
|
|
|
|
if ( rot[0] > ( 64 - 48 ) && rot[0] < ( 64 + 48 ) )
|
|
newX = 1;
|
|
else if ( rot[0] > ( 192 - 48 ) && rot[0] < ( 192 + 48 ) )
|
|
newX = -1;
|
|
|
|
if ( rot[1] >= 192 && rot[1] <= ( 192 + 32 ) )
|
|
newY = 1;
|
|
else if ( rot[1] <= 64 && rot[1] >= 32 )
|
|
newY = -1;
|
|
|
|
if ( 192 <= rot[1] && rot[1] <= 196 || 60 <= rot[1] && rot[1] <= 64 ) { newX = 0; newZ = 0; }
|
|
|
|
byte b1 = level.GetTile((ushort)( x + newX * 2 ), (ushort)( y + newY * 2 ), (ushort)( z + newZ * 2 ));
|
|
byte b2 = level.GetTile((ushort)( x + newX ), (ushort)( y + newY ), (ushort)( z + newZ ));
|
|
if ( b1 == Block.air && b2 == Block.air && level.CheckClear((ushort)( x + newX * 2 ), (ushort)( y + newY * 2 ), (ushort)( z + newZ * 2 )) && level.CheckClear((ushort)( x + newX ), (ushort)( y + newY ), (ushort)( z + newZ )) ) {
|
|
level.Blockchange((ushort)( x + newX * 2 ), (ushort)( y + newY * 2 ), (ushort)( z + newZ * 2 ), Block.rockethead);
|
|
level.Blockchange((ushort)( x + newX ), (ushort)( y + newY ), (ushort)( z + newZ ), Block.fire);
|
|
}
|
|
}
|
|
break;
|
|
case Block.firework:
|
|
if ( level.physics == 5 ) {
|
|
RevertBlock(x, y, z); return;
|
|
}
|
|
if ( level.physics != 0 ) {
|
|
Random rand = new Random();
|
|
int mx = rand.Next(0, 2); int mz = rand.Next(0, 2);
|
|
byte b1 = level.GetTile((ushort)( x + mx - 1 ), (ushort)( y + 2 ), (ushort)( z + mz - 1 ));
|
|
byte b2 = level.GetTile((ushort)( x + mx - 1 ), (ushort)( y + 1 ), (ushort)( z + mz - 1 ));
|
|
if ( b1 == Block.air && b2 == Block.air && level.CheckClear((ushort)( x + mx - 1 ), (ushort)( y + 2 ), (ushort)( z + mz - 1 )) && level.CheckClear((ushort)( x + mx - 1 ), (ushort)( y + 1 ), (ushort)( z + mz - 1 )) ) {
|
|
level.Blockchange((ushort)( x + mx - 1 ), (ushort)( y + 2 ), (ushort)( z + mz - 1 ), Block.firework);
|
|
level.Blockchange((ushort)( x + mx - 1 ), (ushort)( y + 1 ), (ushort)( z + mz - 1 ), Block.lavastill, false, "wait 1 dissipate 100");
|
|
}
|
|
}
|
|
RevertBlock(x, y, z);
|
|
break;
|
|
|
|
case Block.c4det:
|
|
Level.C4.BlowUp(new ushort[] { x, y, z }, level);
|
|
level.Blockchange(x, y, z, Block.air);
|
|
break;
|
|
|
|
default:
|
|
level.Blockchange(this, x, y, z, (byte)( Block.air ));
|
|
break;
|
|
}
|
|
if ( (level.physics == 0 || level.physics == 5) && level.GetTile(x, (ushort)( y - 1 ), z) == Block.dirt )
|
|
level.Blockchange(this, x, (ushort)( y - 1 ), z, Block.grass);
|
|
}
|
|
|
|
void PlaceBlock(byte b, ushort x, ushort y, ushort z, byte type, byte extType) {
|
|
if ( Block.odoor(b) != Block.Zero ) { SendMessage("oDoor here!"); return; }
|
|
switch ( BlockAction ) {
|
|
case 0: //normal
|
|
if ( level.physics == 0 || level.physics == 5 ) {
|
|
switch ( type ) {
|
|
case Block.dirt: //instant dirt to grass
|
|
byte above = level.GetTile(x, (ushort)(y + 1), z), extAbove = 0;
|
|
if (type == Block.custom_block)
|
|
extAbove = level.GetExtTile(x, (ushort)(y + 1), z);
|
|
|
|
if (Block.LightPass(above, extAbove, level.CustomBlockDefs))
|
|
level.Blockchange(this, x, y, z, (byte)Block.grass);
|
|
else
|
|
level.Blockchange(this, x, y, z, (byte)Block.dirt);
|
|
break;
|
|
case Block.staircasestep: //stair handler
|
|
if ( level.GetTile(x, (ushort)( y - 1 ), z) == Block.staircasestep ) {
|
|
SendBlockchange(x, y, z, Block.air); //send the air block back only to the user.
|
|
//level.Blockchange(this, x, y, z, (byte)(Block.air));
|
|
level.Blockchange(this, x, (ushort)( y - 1 ), z, (byte)( Block.staircasefull ));
|
|
break;
|
|
}
|
|
//else
|
|
level.Blockchange(this, x, y, z, type, extType);
|
|
break;
|
|
default:
|
|
level.Blockchange(this, x, y, z, type, extType);
|
|
break;
|
|
}
|
|
} else {
|
|
level.Blockchange(this, x, y, z, type, extType);
|
|
}
|
|
break;
|
|
case 6:
|
|
if ( b == modeType ) { SendBlockchange(x, y, z, b); return; }
|
|
level.Blockchange(this, x, y, z, modeType);
|
|
break;
|
|
case 13: //Small TNT
|
|
level.Blockchange(this, x, y, z, Block.smalltnt);
|
|
break;
|
|
case 14: //Big TNT
|
|
level.Blockchange(this, x, y, z, Block.bigtnt);
|
|
break;
|
|
case 15: //Nuke TNT
|
|
level.Blockchange(this, x, y, z, Block.nuketnt);
|
|
break;
|
|
default:
|
|
Server.s.Log(name + " is breaking something");
|
|
BlockAction = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandleMovement(byte[] message) {
|
|
if ( !loggedIn || trainGrab || following != "" || frozen )
|
|
return;
|
|
/*if (CheckIfInsideBlock())
|
|
{
|
|
this.SendPos(0xFF, (ushort)(clippos[0] - 18), (ushort)(clippos[1] - 18), (ushort)(clippos[2] - 18), cliprot[0], cliprot[1]);
|
|
return;
|
|
}*/
|
|
byte thisid = message[0];
|
|
ushort x = NetUtils.ReadU16(message, 1);
|
|
ushort y = NetUtils.ReadU16(message, 3);
|
|
ushort z = NetUtils.ReadU16(message, 5);
|
|
byte rotx = message[7], roty = message[8];
|
|
|
|
if (Server.Countdown.HandlesMovement(this, x, y, z, rotx, roty))
|
|
return;
|
|
if (Server.ZombieModeOn && Server.zombie.HandlesMovement(this, x, y, z, rotx, roty))
|
|
return;
|
|
|
|
if (OnMove != null) OnMove(this, x, y, z);
|
|
if (PlayerMove != null) PlayerMove(this, x, y, z);
|
|
if (PlayerMoveEvent.events.Count > 0) PlayerMoveEvent.Call(this, x, y, z);
|
|
|
|
if (OnRotate != null) OnRotate(this, rot);
|
|
if (PlayerRotate != null) PlayerRotate(this, rot);
|
|
if (PlayerRotateEvent.events.Count > 0) PlayerRotateEvent.Call(this, rot);
|
|
|
|
if (cancelmove) {
|
|
SendPos(0xFF, pos[0], pos[1], pos[2], rot[0], rot[1]); return;
|
|
}
|
|
pos = new ushort[3] { x, y, z };
|
|
rot = new byte[2] { rotx, roty };
|
|
/*if (!CheckIfInsideBlock()) { clippos = pos; cliprot = rot; }*/
|
|
}
|
|
|
|
internal void CheckSurvival(ushort x, ushort y, ushort z) {
|
|
byte bFeet = GetSurvivalBlock(x, (ushort)(y - 2), z);
|
|
byte bHead = GetSurvivalBlock(x, y, z);
|
|
if (level.PosToInt(x, y, z) != oldIndex || y != oldFallY) {
|
|
byte conv = Block.Convert(bFeet);
|
|
if (conv == Block.air) {
|
|
if (y < oldFallY)
|
|
fallCount++;
|
|
else if (y > oldFallY) // flying up, for example
|
|
fallCount = 0;
|
|
oldFallY = y;
|
|
drownCount = 0;
|
|
return;
|
|
} else if (!(conv == Block.water || conv == Block.waterstill ||
|
|
conv == Block.lava || conv == Block.lavastill)) {
|
|
if (fallCount > level.fall)
|
|
HandleDeath(Block.air, null, false, true);
|
|
fallCount = 0;
|
|
drownCount = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (Block.Convert(bHead)) {
|
|
case Block.water:
|
|
case Block.waterstill:
|
|
case Block.lava:
|
|
case Block.lavastill:
|
|
fallCount = 0;
|
|
drownCount++;
|
|
if (drownCount > level.drown * (100/3)) {
|
|
HandleDeath(Block.water);
|
|
drownCount = 0;
|
|
}
|
|
break;
|
|
case Block.air:
|
|
drownCount = 0;
|
|
break;
|
|
default:
|
|
fallCount = 0;
|
|
drownCount = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
byte GetSurvivalBlock(ushort x, ushort y, ushort z) {
|
|
if (y >= ushort.MaxValue - 512) return Block.blackrock;
|
|
if (y >= level.Height) return Block.air;
|
|
return level.GetTile(x, y, z);
|
|
}
|
|
|
|
internal void CheckBlock(ushort x, ushort y, ushort z) {
|
|
byte b = level.GetTile(x, y, z);
|
|
byte b1 = level.GetTile(x, (ushort)(y - 1), z);
|
|
|
|
if ( Block.Mover(b) || Block.Mover(b1) ) {
|
|
if ( Block.DoorAirs(b) != 0 )
|
|
level.Blockchange(x, y, z, Block.DoorAirs(b));
|
|
if ( Block.DoorAirs(b1) != 0 )
|
|
level.Blockchange(x, (ushort)(y - 1), z, Block.DoorAirs(b1));
|
|
|
|
if ( level.PosToInt( x, y, z ) != oldIndex ) {
|
|
if ( b == Block.air_portal || b == Block.water_portal || b == Block.lava_portal ) {
|
|
HandlePortal(this, x, y, z, b);
|
|
} else if ( b1 == Block.air_portal || b1 == Block.water_portal || b1 == Block.lava_portal ) {
|
|
HandlePortal(this, x, (ushort)(y - 1), z, b1);
|
|
}
|
|
|
|
if ( b == Block.MsgAir || b == Block.MsgWater || b == Block.MsgLava ) {
|
|
HandleMsgBlock(this, x, y, z, b);
|
|
} else if ( b1 == Block.MsgAir || b1 == Block.MsgWater || b1 == Block.MsgLava ) {
|
|
HandleMsgBlock(this, x, (ushort)(y - 1), z, b1);
|
|
} else if ( b == Block.checkpoint ) {
|
|
useCheckpointSpawn = true;
|
|
checkpointX = x; checkpointY = y; checkpointZ = z;
|
|
int index = level.PosToInt(x, y, z);
|
|
if (index != lastCheckpointIndex) {
|
|
SendSpawn(0xFF, color + name, pos[0], (ushort)((y - 1) * 32 + 51), pos[2], rot[0], rot[1]);
|
|
lastCheckpointIndex = index;
|
|
}
|
|
} else if ( b1 == Block.checkpoint ) {
|
|
useCheckpointSpawn = true;
|
|
checkpointX = x; checkpointY = (ushort)(y + 1); checkpointZ = z;
|
|
int index = level.PosToInt(x, (ushort)(y - 1), z);
|
|
if (index != lastCheckpointIndex) {
|
|
SendSpawn(0xFF, color + name, pos[0], (ushort)((y - 1) * 32 + 51), pos[2], rot[0], rot[1]);
|
|
lastCheckpointIndex = index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( ( b == Block.tntexplosion || b1 == Block.tntexplosion ) && PlayingTntWars ) { }
|
|
else if ( Block.Death(b) ) HandleDeath(b);
|
|
else if ( Block.Death(b1) ) HandleDeath(b1);
|
|
}
|
|
|
|
public void HandleDeath(byte b, string customMessage = "", bool explode = false, bool immediate = false) {
|
|
ushort x = (ushort)(pos[0] / 32), y = (ushort)(pos[1] / 32), z = (ushort)(pos[2] / 32);
|
|
if ( OnDeath != null )
|
|
OnDeath(this, b);
|
|
if ( PlayerDeath != null )
|
|
PlayerDeath(this, b);
|
|
OnPlayerDeathEvent.Call(this, b);
|
|
if ( Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this) )
|
|
return;
|
|
|
|
if ( immediate || lastDeath.AddSeconds(2) < DateTime.Now ) {
|
|
|
|
if ( level.Killer && !invincible && !hidden ) {
|
|
|
|
switch ( b ) {
|
|
case Block.tntexplosion: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " &cblew into pieces.", false); break;
|
|
case Block.deathair: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " walked into &cnerve gas and suffocated.", false); break;
|
|
case Block.deathwater:
|
|
case Block.activedeathwater: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " stepped in &dcold water and froze.", false); break;
|
|
case Block.deathlava:
|
|
case Block.activedeathlava:
|
|
case Block.fastdeathlava: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " stood in &cmagma and melted.", false); break;
|
|
case Block.magma: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was hit by &cflowing magma and melted.", false); break;
|
|
case Block.geyser: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was hit by &cboiling water and melted.", false); break;
|
|
case Block.birdkill: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was hit by a &cphoenix and burnt.", false); break;
|
|
case Block.train: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was hit by a &ctrain.", false); break;
|
|
case Block.fishshark: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was eaten by a &cshark.", false); break;
|
|
case Block.fire: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " burnt to a &ccrisp.", false); break;
|
|
case Block.rockethead: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was &cin a fiery explosion.", false); level.MakeExplosion(x, y, z, 0); break;
|
|
case Block.zombiebody: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " died due to lack of &5brain.", false); break;
|
|
case Block.creeper: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was killed &cb-SSSSSSSSSSSSSS", false); level.MakeExplosion(x, y, z, 1); break;
|
|
case Block.air: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " hit the floor &chard.", false); break;
|
|
case Block.water: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " &cdrowned.", false); break;
|
|
case Block.Zero: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was &cterminated", false); break;
|
|
case Block.fishlavashark: Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + " was eaten by a ... LAVA SHARK?!", false); break;
|
|
case Block.rock:
|
|
if ( explode ) level.MakeExplosion(x, y, z, 1);
|
|
SendChatFrom(this, this.FullName + Server.DefaultColor + customMessage, false);
|
|
break;
|
|
case Block.stone:
|
|
if ( explode ) level.MakeExplosion(x, y, z, 1);
|
|
Chat.GlobalChatLevel(this, this.FullName + Server.DefaultColor + customMessage, false);
|
|
break;
|
|
}
|
|
if ( team != null && this.level.ctfmode ) {
|
|
//if (carryingFlag)
|
|
//{
|
|
// level.ctfgame.DropFlag(this, hasflag);
|
|
//}
|
|
team.SpawnPlayer(this);
|
|
//this.health = 100;
|
|
}
|
|
else if ( Server.Countdown.playersleftlist.Contains(this) ) {
|
|
Server.Countdown.Death(this);
|
|
Command.all.Find("spawn").Use(this, "");
|
|
}
|
|
else if ( PlayingTntWars ) {
|
|
TntWarsKillStreak = 0;
|
|
TntWarsScoreMultiplier = 1f;
|
|
}
|
|
else if ( Server.lava.active && Server.lava.HasPlayer(this) ) {
|
|
if ( !Server.lava.IsPlayerDead(this) ) {
|
|
Server.lava.KillPlayer(this);
|
|
Command.all.Find("spawn").Use(this, "");
|
|
}
|
|
}
|
|
else {
|
|
Command.all.Find("spawn").Use(this, "");
|
|
overallDeath++;
|
|
}
|
|
|
|
if ( Server.deathcount )
|
|
if ( overallDeath > 0 && overallDeath % 10 == 0 )
|
|
SendChatFrom(this, this.FullName + Server.DefaultColor + " has died &3" + overallDeath + " times", false);
|
|
}
|
|
lastDeath = DateTime.Now;
|
|
|
|
}
|
|
}
|
|
|
|
/* void HandleFly(Player p, ushort x, ushort y, ushort z) {
|
|
FlyPos pos;
|
|
|
|
ushort xx; ushort yy; ushort zz;
|
|
|
|
TempFly.Clear();
|
|
|
|
if (!flyGlass) y = (ushort)(y + 1);
|
|
|
|
for (yy = y; yy >= (ushort)(y - 1); --yy)
|
|
for (xx = (ushort)(x - 2); xx <= (ushort)(x + 2); ++xx)
|
|
for (zz = (ushort)(z - 2); zz <= (ushort)(z + 2); ++zz)
|
|
if (p.level.GetTile(xx, yy, zz) == Block.air) {
|
|
pos.x = xx; pos.y = yy; pos.z = zz;
|
|
TempFly.Add(pos);
|
|
}
|
|
|
|
FlyBuffer.ForEach(delegate(FlyPos pos2) {
|
|
try { if (!TempFly.Contains(pos2)) SendBlockchange(pos2.x, pos2.y, pos2.z, Block.air); } catch { }
|
|
});
|
|
|
|
FlyBuffer.Clear();
|
|
|
|
TempFly.ForEach(delegate(FlyPos pos3){
|
|
FlyBuffer.Add(pos3);
|
|
});
|
|
|
|
if (flyGlass) {
|
|
FlyBuffer.ForEach(delegate(FlyPos pos1) {
|
|
try { SendBlockchange(pos1.x, pos1.y, pos1.z, Block.glass); } catch { }
|
|
});
|
|
} else {
|
|
FlyBuffer.ForEach(delegate(FlyPos pos1) {
|
|
try { SendBlockchange(pos1.x, pos1.y, pos1.z, Block.waterstill); } catch { }
|
|
});
|
|
}
|
|
} */
|
|
|
|
void HandleChat(byte[] message) {
|
|
try {
|
|
if ( !loggedIn ) return;
|
|
byte continued = message[0];
|
|
string text = GetString(message, 1);
|
|
|
|
// handles the /womid client message, which displays the WoM vrersion
|
|
if ( text.Truncate(6) == "/womid" ) {
|
|
string version = (text.Length <= 21 ? text.Substring(text.IndexOf(' ') + 1) : text.Substring(7, 15));
|
|
Player.GlobalMessage(Colors.red + "[INFO] " + color + DisplayName + "%f is using wom client");
|
|
Player.GlobalMessage(Colors.red + "[INFO] %fVersion: " + version);
|
|
Server.s.Log(Colors.red + "[INFO] " + color + DisplayName + "%f is using wom client");
|
|
Server.s.Log(Colors.red + "[INFO] %fVersion: " + version);
|
|
UsingWom = true;
|
|
WoMVersion = version.Split('-')[1];
|
|
return;
|
|
}
|
|
|
|
if( HasCpeExt(CpeExt.LongerMessages) && continued != 0 ) {
|
|
if (text.Length < 64) storedMessage = storedMessage + text + " ";
|
|
else storedMessage = storedMessage + text;
|
|
return;
|
|
}
|
|
|
|
if ( storedMessage != "" ) {
|
|
if ( !text.EndsWith(">") && !text.EndsWith("<") ) {
|
|
text = storedMessage.Replace("|>|", " ").Replace("|<|", "") + text;
|
|
storedMessage = "";
|
|
}
|
|
}
|
|
//if (text.StartsWith(">") || text.StartsWith("<")) return;
|
|
if (text.EndsWith(">"))
|
|
{
|
|
storedMessage += text.Replace(">", "|>|");
|
|
SendMessage(Colors.teal + "Partial message: " + Colors.white + storedMessage.Replace("|>|", " ").Replace("|<|", ""));
|
|
return;
|
|
}
|
|
if (text.EndsWith("<"))
|
|
{
|
|
storedMessage += text.Replace("<", "|<|");
|
|
SendMessage(Colors.teal + "Partial message: " + Colors.white + storedMessage.Replace("|<|", "").Replace("|>|", " "));
|
|
return;
|
|
}
|
|
|
|
text = Regex.Replace(text, @"\s\s+", " ");
|
|
if ( text.Any(ch => ch == '&') ) {
|
|
Kick("Illegal character in chat message!");
|
|
return;
|
|
}
|
|
if ( text.Length == 0 )
|
|
return;
|
|
afkCount = 0;
|
|
|
|
if ( text != "/afk" ) {
|
|
if ( Server.afkset.Contains(this.name) ) {
|
|
Server.afkset.Remove(this.name);
|
|
Player.GlobalMessage("-" + this.color + this.DisplayName + Server.DefaultColor + "- is no longer AFK");
|
|
Server.IRC.Say(this.DisplayName + " is no longer AFK");
|
|
}
|
|
}
|
|
// Typing //Command appears in chat as /command
|
|
// Suggested by McMrCat
|
|
if ( text.StartsWith("//") ) {
|
|
text = text.Remove(0, 1);
|
|
goto hello;
|
|
}
|
|
// Typing / will act as /repeat
|
|
if ( text == "/" ) {
|
|
HandleCommand("repeat", "");
|
|
return;
|
|
}
|
|
if ( text[0] == '/' || text[0] == '!' ) {
|
|
text = text.Remove(0, 1);
|
|
|
|
int pos = text.IndexOf(' ');
|
|
if ( pos == -1 ) {
|
|
HandleCommand(text.ToLower(), "");
|
|
return;
|
|
}
|
|
string cmd = text.Substring(0, pos).ToLower();
|
|
string msg = text.Substring(pos + 1);
|
|
HandleCommand(cmd, msg);
|
|
return;
|
|
}
|
|
hello:
|
|
// People who are muted can't speak or vote
|
|
if ( muted ) { this.SendMessage("You are muted."); return; } //Muted: Only allow commands
|
|
|
|
// Lava Survival map vote recorder
|
|
if ( Server.lava.HasPlayer(this) && Server.lava.HasVote(text.ToLower()) ) {
|
|
if ( Server.lava.AddVote(this, text.ToLower()) ) {
|
|
SendMessage("Your vote for &5" + text.ToLower().Capitalize() + Server.DefaultColor + " has been placed. Thanks!");
|
|
Server.lava.map.ChatLevelOps(name + " voted for &5" + text.ToLower().Capitalize() + Server.DefaultColor + ".");
|
|
return;
|
|
}
|
|
else {
|
|
SendMessage("&cYou already voted!");
|
|
return;
|
|
}
|
|
}
|
|
if (VoteHandles(text)) return;
|
|
|
|
// Put this after vote collection so that people can vote even when chat is moderated
|
|
if ( Server.chatmod && !voice ) { this.SendMessage("Chat moderation is on, you cannot speak."); return; }
|
|
|
|
// Filter out bad words
|
|
if ( Server.profanityFilter ) {
|
|
text = ProfanityFilter.Parse(text);
|
|
}
|
|
|
|
if ( Server.checkspam ) {
|
|
//if (consecutivemessages == 0)
|
|
//{
|
|
// consecutivemessages++;
|
|
//}
|
|
if ( Player.lastMSG == this.name ) {
|
|
consecutivemessages++;
|
|
} else {
|
|
consecutivemessages--;
|
|
}
|
|
|
|
if ( this.consecutivemessages >= Server.spamcounter ) {
|
|
int total = Server.mutespamtime;
|
|
Command.all.Find("mute").Use(null, this.name);
|
|
Player.GlobalMessage(this.color + this.DisplayName + Server.DefaultColor + " has been &0muted &efor spamming!");
|
|
muteTimer.Elapsed += delegate {
|
|
total--;
|
|
if ( total <= 0 ) {
|
|
muteTimer.Stop();
|
|
if ( this.muted ) {
|
|
Command.all.Find("mute").Use(null, this.name);
|
|
}
|
|
this.consecutivemessages = 0;
|
|
Player.SendMessage(this, "Remember, no &cspamming &e" + "next time!");
|
|
}
|
|
};
|
|
muteTimer.Start();
|
|
return;
|
|
}
|
|
}
|
|
Player.lastMSG = this.name;
|
|
|
|
if( Chat.HandleModes(this, text) )
|
|
return;
|
|
|
|
if ( InGlobalChat ) {
|
|
Command.all.Find("global").Use(this, text); //Didn't want to rewrite the whole command... you lazy bastard :3
|
|
return;
|
|
}
|
|
|
|
if ( text[0] == ':' ) {
|
|
if ( PlayingTntWars ) {
|
|
string newtext = text;
|
|
if ( text[0] == ':' ) newtext = text.Remove(0, 1).Trim();
|
|
TntWarsGame it = TntWarsGame.GetTntWarsGame(this);
|
|
if ( it.GameMode == TntWarsGame.TntWarsGameMode.TDM ) {
|
|
TntWarsGame.player pl = it.FindPlayer(this);
|
|
foreach ( TntWarsGame.player p in it.Players ) {
|
|
if ( pl.Red && p.Red ) SendMessage(p.p, "To Team " + Colors.red + "-" + color + name + Colors.red + "- " + Server.DefaultColor + newtext);
|
|
if ( pl.Blue && p.Blue ) SendMessage(p.p, "To Team " + Colors.blue + "-" + color + name + Colors.blue + "- " + Server.DefaultColor + newtext);
|
|
}
|
|
Server.s.Log("[TNT Wars] [TeamChat (" + ( pl.Red ? "Red" : "Blue" ) + ") " + name + " " + newtext);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*if (this.teamchat)
|
|
{
|
|
if (team == null)
|
|
{
|
|
Player.SendMessage(this, "You are not on a team.");
|
|
return;
|
|
}
|
|
foreach (Player p in team.players)
|
|
{
|
|
Player.SendMessage(p, "(" + team.teamstring + ") " + this.color + this.name + ":&f " + text);
|
|
}
|
|
return;
|
|
}*/
|
|
if ( this.joker ) {
|
|
if ( File.Exists("text/joker.txt") ) {
|
|
Server.s.Log("<JOKER>: " + this.name + ": " + text);
|
|
Chat.GlobalMessageOps(Server.DefaultColor + "<&aJ&bO&cK&5E&9R" + Server.DefaultColor + ">: " + this.color + this.DisplayName + ":&f " + text);
|
|
FileInfo jokertxt = new FileInfo("text/joker.txt");
|
|
StreamReader stRead = jokertxt.OpenText();
|
|
List<string> lines = new List<string>();
|
|
Random rnd = new Random();
|
|
int i = 0;
|
|
|
|
while ( !( stRead.Peek() == -1 ) )
|
|
lines.Add(stRead.ReadLine());
|
|
|
|
stRead.Close();
|
|
stRead.Dispose();
|
|
|
|
if ( lines.Count > 0 ) {
|
|
i = rnd.Next(lines.Count);
|
|
text = lines[i];
|
|
}
|
|
|
|
}
|
|
else { File.Create("text/joker.txt").Dispose(); }
|
|
|
|
}
|
|
|
|
//chatroom stuff
|
|
if ( this.Chatroom != null ) {
|
|
Chat.ChatRoom(this, text, true, this.Chatroom);
|
|
return;
|
|
}
|
|
|
|
if ( !level.worldChat ) {
|
|
Server.s.Log("<" + name + ">[level] " + text);
|
|
Chat.GlobalChatLevel(this, text, true);
|
|
return;
|
|
}
|
|
|
|
if ( text[0] == '%' ) {
|
|
string newtext = text;
|
|
if (!Server.worldChat) {
|
|
newtext = text.Remove(0, 1).Trim();
|
|
Chat.GlobalChatWorld(this, newtext, true);
|
|
} else {
|
|
SendChatFrom(this, newtext);
|
|
}
|
|
Server.s.Log("<" + name + "> " + newtext);
|
|
//IRCBot.Say("<" + name + "> " + newtext);
|
|
if (OnChat != null) OnChat(this, text);
|
|
if (PlayerChat != null) PlayerChat(this, text);
|
|
if (OnPlayerChatEvent.events.Count > 0) OnPlayerChatEvent.Call(this, text);
|
|
return;
|
|
}
|
|
Server.s.Log("<" + name + "> " + text);
|
|
if (OnChat != null) OnChat(this, text);
|
|
if (PlayerChat != null) PlayerChat(this, text);
|
|
if (OnPlayerChatEvent.events.Count > 0) OnPlayerChatEvent.Call(this, text);
|
|
|
|
if (cancelchat) {
|
|
cancelchat = false; return;
|
|
}
|
|
if (Server.worldChat) {
|
|
SendChatFrom(this, text);
|
|
} else {
|
|
Chat.GlobalChatLevel(this, text, true);
|
|
}
|
|
|
|
//IRCBot.Say(name + ": " + text);
|
|
}
|
|
catch ( Exception e ) { Server.ErrorLog(e); Player.GlobalMessage("An error occurred: " + e.Message); }
|
|
}
|
|
|
|
bool VoteHandles(string text) {
|
|
if (Server.voteKickInProgress && text.Length == 1) {
|
|
if (text.ToLower() == "y") {
|
|
this.voteKickChoice = VoteKickChoice.Yes;
|
|
SendMessage("Thanks for voting!");
|
|
return true;
|
|
} else if (text.ToLower() == "n") {
|
|
this.voteKickChoice = VoteKickChoice.No;
|
|
SendMessage("Thanks for voting!");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (Server.lava.HasPlayer(this) && Server.lava.HasVote(text.ToLower()) ) {
|
|
if (Server.lava.AddVote(this, text.ToLower())) {
|
|
SendMessage("Your vote for &5" + text.ToLower().Capitalize() + Server.DefaultColor + " has been placed. Thanks!");
|
|
Server.lava.map.ChatLevelOps(name + " voted for &5" + text.ToLower().Capitalize() + Server.DefaultColor + ".");
|
|
return true;
|
|
} else {
|
|
SendMessage("&cYou already voted!");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (Server.voting) {
|
|
string test = text.ToLower();
|
|
if (CheckVote(test, this, "y", "yes", ref Server.YesVotes) ||
|
|
CheckVote(test, this, "n", "no", ref Server.NoVotes)) return true;
|
|
|
|
if (!voice && (test == "y" || test == "n" || test == "yes" || test == "no")) {
|
|
SendMessage("Chat moderation is on while voting is on!"); return true;
|
|
}
|
|
}
|
|
|
|
if (Server.votingforlevel && Server.zombie.HandlesChatMessage(this, text))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public void HandleCommand(string cmd, string message) {
|
|
cmd = cmd.ToLower();
|
|
try {
|
|
if (cmd == "") { SendMessage("No command entered."); return; }
|
|
if (Server.agreetorulesonentry && !agreed && !(cmd == "agree" || cmd == "rules" || cmd == "disagree")) {
|
|
SendMessage("You must read /rules then agree to them with /agree!"); return;
|
|
}
|
|
if (jailed) {
|
|
SendMessage("You cannot use any commands while jailed."); return;
|
|
}
|
|
if (Server.verifyadmins && adminpen && !(cmd == "pass" || cmd == "setpass")) {
|
|
SendMessage("&cYou must use &a/pass [Password]&c to verify!"); return;
|
|
}
|
|
|
|
//DO NOT REMOVE THE TWO COMMANDS BELOW, /PONY AND /RAINBOWDASHLIKESCOOLTHINGS. -EricKilla
|
|
if (cmd == "pony") {
|
|
if ( ponycount < 2 ) {
|
|
GlobalMessage(color + DisplayName + " %Sjust so happens to be a proud brony! Everyone give " + color + name + " %Sa brohoof!");
|
|
ponycount += 1;
|
|
} else {
|
|
SendMessage("You have used this command 2 times. You cannot use it anymore! Sorry, Brony!");
|
|
}
|
|
return;
|
|
}
|
|
if (cmd == "rainbowdashlikescoolthings") {
|
|
if ( rdcount < 2 ) {
|
|
GlobalMessage("&1T&2H&3I&4S &5S&6E&7R&8V&9E&aR &bJ&cU&dS&eT &fG&0O&1T &22&30 &4P&CE&7R&DC&EE&9N&1T &5C&6O&7O&8L&9E&aR&b!");
|
|
rdcount += 1;
|
|
} else {
|
|
SendMessage("You have used this command 2 times. You cannot use it anymore! Sorry, Brony!");
|
|
}
|
|
return;
|
|
}
|
|
|
|
string shortcut = Command.all.FindShort(cmd);
|
|
if (shortcut != "") cmd = shortcut;
|
|
|
|
byte bindIndex;
|
|
if (byte.TryParse(cmd, out bindIndex) && bindIndex < 10) {
|
|
if (messageBind[bindIndex] == null) { SendMessage("No command is bound to: /" + cmd); return; }
|
|
cmd = cmdBind[bindIndex];
|
|
message = messageBind[bindIndex] + " " + message;
|
|
message = message.TrimEnd(' ');
|
|
}
|
|
|
|
Alias alias = Alias.Find(cmd);
|
|
if (alias != null) {
|
|
string[] pars = alias.Command.Split(trimChars, 2);
|
|
cmd = pars[0];
|
|
if (pars.Length > 1)
|
|
message = message == "" ? pars[1] : pars[1] + " " + message;
|
|
}
|
|
|
|
if (OnCommand != null) OnCommand(cmd, this, message);
|
|
if (PlayerCommand != null) PlayerCommand(cmd, this, message);
|
|
OnPlayerCommandEvent.Call(cmd, this, message);
|
|
if (cancelcommand) {
|
|
cancelcommand = false; return;
|
|
}
|
|
|
|
Command command = Command.all.Find(cmd);
|
|
if (command != null) {
|
|
UseCommand(command, cmd, message);
|
|
} else if (Block.Byte(cmd.ToLower()) != Block.Zero) {
|
|
HandleCommand("mode", cmd.ToLower());
|
|
} else if (MapCommand(ref cmd, ref message)) {
|
|
HandleCommand(cmd, message);
|
|
} else {
|
|
SendMessage("Unknown command \"" + cmd + "\"!");
|
|
}
|
|
}
|
|
catch ( Exception e ) { Server.ErrorLog(e); SendMessage("Command failed."); }
|
|
}
|
|
|
|
void UseCommand(Command command, string cmd, string message) {
|
|
if (!group.CanExecute(command)) {
|
|
SendMessage("You are not allowed to use \"" + cmd + "\"."); return;
|
|
}
|
|
if (cmd != "repeat") lastCMD = cmd + " " + message;
|
|
|
|
if (level.IsMuseum && !command.museumUsable ) {
|
|
SendMessage("Cannot use this command while in a museum!"); return;
|
|
}
|
|
if ((joker || muted) && cmd == "me") {
|
|
SendMessage("Cannot use /me while muted or jokered."); return;
|
|
}
|
|
if (!(cmd == "pass" || cmd == "setpass")) {
|
|
Server.s.CommandUsed(name + " used /" + cmd + " " + message);
|
|
}
|
|
|
|
try { //opstats patch (since 5.5.11)
|
|
if (Server.opstats.Contains(cmd) || (cmd == "review" && message.ToLower() == "next" && Server.reviewlist.Count > 0)) {
|
|
Database.AddParams("@Time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
Database.AddParams("@Name", name);
|
|
Database.AddParams("@Cmd", cmd);
|
|
Database.AddParams("@Cmdmsg", message);
|
|
Database.executeQuery("INSERT INTO Opstats (Time, Name, Cmd, Cmdmsg) VALUES (@Time, @Name, @Cmd, @Cmdmsg)");
|
|
}
|
|
} catch { }
|
|
|
|
Thread thread = new Thread(
|
|
new ThreadStart(delegate {
|
|
try {
|
|
command.Use(this, message);
|
|
} catch (Exception e) {
|
|
Server.ErrorLog(e);
|
|
Player.SendMessage(this, "An error occured when using the command!");
|
|
Player.SendMessage(this, e.GetType() + ": " + e.Message);
|
|
}
|
|
}));
|
|
thread.Name = "MCG_Command";
|
|
thread.Start();
|
|
}
|
|
|
|
bool MapCommand(ref string cmd, ref string message) {
|
|
switch (cmd) {
|
|
case "guest":
|
|
case "builder":
|
|
case "advbuilder":
|
|
case "adv":
|
|
case "operator":
|
|
case "op":
|
|
case "super":
|
|
case "superop": message = cmd + " " + message; cmd = "setrank"; return true;
|
|
case "cut": cmd = "copy"; message = "cut"; return true;
|
|
case "admins": message = "superop"; cmd = "viewranks"; return true;
|
|
case "ops": message = "op"; cmd = "viewranks"; return true;
|
|
case "banned": message = cmd; cmd = "viewranks"; return true;
|
|
case "ps": message = "ps " + message; cmd = "map"; return true;
|
|
|
|
case "bhb":
|
|
case "hbox": cmd = "cuboid"; message = "hollow"; return true;
|
|
case "blb":
|
|
case "box": cmd = "cuboid"; return true;
|
|
case "sphere": cmd = "spheroid"; return true;
|
|
case "cmdlist":
|
|
case "commands": cmd = "help"; message = "commands"; return true;
|
|
case "cmdhelp": cmd = "help"; return true;
|
|
case "worlds":
|
|
case "mapsave": cmd = "save"; return true;
|
|
case "mapload": cmd = "load"; return true;
|
|
case "colour": cmd = "color"; return true;
|
|
case "materials": cmd = "blocks"; return true;
|
|
case "zz": cmd = "static"; message = "cuboid " + message; return true;
|
|
case "fetch": cmd = "summon"; return true;
|
|
case "ranks": cmd = "help"; message = "ranks"; return true;
|
|
case "j":
|
|
case "join": cmd = "goto"; return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|