diff --git a/HttpBins/HttpServer.xml b/HttpBins/HttpServer.xml index e291a2902..c5e514436 100644 --- a/HttpBins/HttpServer.xml +++ b/HttpBins/HttpServer.xml @@ -1,6188 +1,6188 @@ - - - - HttpServer - - - - - Used by to filter out unwanted connections. - - - - - Initializes a new instance of the class. - - The socket. - - - - Gets or sets if socket can be accepted. - - - - - Gets socket. - - - - - A request have been received. - - - - - - - Initializes a new instance of the class. - - context that received the request. - Received request. - Response to send. - - - - Gets context that received the request. - - - Do not forget to set to true if you are sending - back a response manually through . - - - - - Gets or sets if the request have been handled. - - - The library will not attempt to send the response object - back to the client if this property is set to true. - - - - - Gets request object. - - - - - Gets response object. - - - - - Cookies that should be set. - - - - - Adds a cookie in the collection. - - cookie to add - cookie is null - Name and Content must be specified. - - - - Copy a request cookie - - - When the cookie should expire - - - - Remove all cookies - - - - - Gets a collection enumerator on the cookie list. - - collection enumerator - - - - Returns an enumerator that iterates through the collection. - - - - A that can be used to iterate through the collection. - - 1 - - - - Gets the count of cookies in the collection. - - - - - Gets the cookie of a given identifier. - - Cookie if found; otherwise null. - - - - An exception that can't be handled by the library have been thrown. - - - - - Initializes a new instance of the class. - - The exception. - - - - Gets caught exception. - - - - - Data decoded from a POST body. - - - - - Initializes a new instance of the class. - - - - - Gets or sets decoded files. - - - - - Gets or sets decoded parameters. - - - - - Stores sessions in files. - - - All session parameters must be serializable. - - - - - Stores sessions in your favorite store - - - - - - - - Saves the specified session. - - The session. - - - - Touches the specified session - - Session id. - - Used to prevent sessions from expiring. - - - - - Loads a session - - Session id. - Session if found; otherwise null. - - - - Delete a session - - Id of session - - - - Saves the specified session. - - The session. - - - - Touches the specified session - - Session id. - - Used to prevent sessions from expiring. - - - - - Loads a session - - Session id. - Session if found; otherwise null. - - - - HTTP methods. - - - - - Unknown method - - - - - Posting data - - - - - Get data - - - - - Update data - - - - - Remove data - - - - - Get only HTTP headers. - - - - - Options HTTP 1.1 header. - - - - - Http listener. - - - - - Http listener - - - - - Start listener. - - Number of pending accepts. - - Make sure that you are subscribing on first. - - Listener have already been started. - Failed to start socket. - Invalid port number. - - - - Stop listener. - - - - - Gets listener address. - - - - - Gets if listener is secure. - - - - - Gets if listener have been started. - - - - - Gets or sets logger. - - - - - Gets listening port. - - - - - Gets the maximum content size. - - The content length limit. - - Used when responding to 100-continue. - - - - - A new request have been received. - - - - - Can be used to reject certain clients. - - - - - A HTTP exception have been thrown. - - - Fill the body with a user friendly error page, or redirect to somewhere else. - - - - - Initializes a new instance of the class. - - The address. - The port. - - - - Initializes a new instance of the class. - - The address. - The port. - The HTTP factory. - - - - Creates a new instance with default factories. - - Address that the listener should accept connections on. - Port that listener should accept connections on. - Created HTTP listener. - - - - Creates a new instance with default factories. - - Address that the listener should accept connections on. - Port that listener should accept connections on. - Factory used to create different types in the framework. - Created HTTP listener. - - - - Creates a new instance with default factories. - - Address that the listener should accept connections on. - Port that listener should accept connections on. - Certificate to use - Created HTTP listener. - - - - Create a new context - - Accepted socket - A new context. - - - Throwing exception if in debug mode and not exception handler have been specified. - - - - Start listener. - - Number of pending accepts. - - Make sure that you are subscribing on first. - - Listener have already been started. - Failed to start socket. - Invalid port number. - - - - Stop listener. - - - - - Gets HTTP factory used to create types used by this HTTP library. - - - - - Gets or sets the maximum number of bytes that the request body can contain. - - The content length limit. - - - Used when responding to 100-continue. - - - 0 = turned off. - - - - - - Gets listener address. - - - - - Gets if listener is secure. - - - - - Gets if listener have been started. - - - - - Gets or sets logger. - - - - - Gets listening port. - - - - - A new request have been received. - - - - - Can be used to reject certain clients. - - - - - A HTTP exception have been thrown. - - - Fill the body with a user friendly error page, or redirect to somewhere else. - - - - - Client asks if he may continue. - - - If the body is too large or anything like that you should respond . - - - - - Contents of a cookie header. - - - - - Header in a message - - - Important! Each header should override ToString() - and return it's data correctly formatted as a HTTP header value. - - - - - Gets header name - - - - - Gets value as it would be sent back to client. - - - - - Initializes a new instance of the class. - - The collection. - collection is null. - - - - Gets cookie collection - - - - - Gets header name - - - - - Gets value as it would be sent back to client. - - - - - - Request couldn't be parsed successfully. - - - - - Exception thrown from HTTP server. - - - - - Initializes a new instance of the class. - - HTTP status code. - Exception description. - - - - Initializes a new instance of the class. - - HTTP status code. - Exception description. - Inner exception. - - - - Gets HTTP status code. - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Exception description. - - - - Something failed during parsing. - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Inner exception. - - - - Used to parse header values - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Collection of body decoders. - - - Body decoders are used to parse request body and convert it - into a and a . - - - - - Add another body decoder. - - - - - - Decode body stream - - Stream containing the content - Content type header - Stream encoding - Decoded data. - Body format is invalid for the specified content type. - Something unexpected failed. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Gets number of decoders. - - - - - Custom network stream to mark sockets as reusable when disposing the stream. - - - - - Creates a new instance of the class for the specified . - - - The that the will use to send and receive data. - - - The parameter is null. - - - The parameter is not connected. - -or- - The property of the parameter is not . - -or- - The parameter is in a nonblocking state. - - - - - Initializes a new instance of the class for the specified with the specified ownership. - - - The that the will use to send and receive data. - - - Set to true to indicate that the will take ownership of the ; otherwise, false. - - - The parameter is null. - - - The parameter is not connected. - -or- - the value of the property of the parameter is not . - -or- - the parameter is in a nonblocking state. - - - - - Creates a new instance of the class for the specified with the specified access rights. - - - The that the will use to send and receive data. - - - A bitwise combination of the values that specify the type of access given to the over the provided . - - - The parameter is null. - - - The parameter is not connected. - -or- - the property of the parameter is not . - -or- - the parameter is in a nonblocking state. - - - - - Creates a new instance of the class for the specified with the specified access rights and the specified ownership. - - - The that the will use to send and receive data. - - - A bitwise combination of the values that specifies the type of access given to the over the provided . - - - Set to true to indicate that the will take ownership of the ; otherwise, false. - - - The parameter is null. - - - The parameter is not connected. - -or- - The property of the parameter is not . - -or- - The parameter is in a nonblocking state. - - - - - Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. - - - - - Releases the unmanaged resources used by the and optionally releases the managed resources. - - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - - Parses query string - - - - - Parse a query string - - string to parse - A collection - reader is null. - - - - Parse a query string - - string to parse - A collection - queryString is null. - - - - Convention over configuration server. - - - Used to make it easy to create and use a web server. - - All resources must exist in the "YourProject.Content" namespace (or a subdirectory called "Content" relative to yourapp.exe). - - - - - - Http server. - - - - - Initializes a new instance of the class. - - Factory used to create objects used in this library. - - - - Initializes a new instance of the class. - - - - - Add a decoder. - - decoder to add - - Adding zero decoders will make the server add the - default ones which is and . - - - - - Add a new router. - - Router to add - Server have been started. - - - - Add a file module - - Module to add - module is null. - Cannot add modules when server have been started. - - - - Add a HTTP listener. - - - Listener have been started. - - - - An error have occurred and we need to send a result pack to the client - - The context. - The exception. - - Invoke base class () to send the contents - of . - - - - - Called before anything else. - - The context. - - Looks after a in the request and will - use the if found. - - - - - All server modules are about to be invoked. - - The context. - - Called when routers have been invoked but no modules yet. - - - - - A request have arrived but not yet been processed yet. - - The context. - - Default implementation adds a Date header and Server header. - - - - - Go through all modules and check if any of them can handle the current request. - - - - - - - Process result (check if it should be sent back or not) - - - - true if request was processed properly.; otherwise false. - - - - Processes all routers. - - Request context. - Processing result. - - - - Requests authentication from the user. - - Host/domain name that the server hosts. - - Used when calculating hashes in Digest authentication. - - - - - - - Send a response. - - - - - - - - Start http server. - - Number of pending connections. - - - - Stops the server - - true if all modules should be removed. - - - - Gets the authentication provider. - - - A authentication provider is used to keep track of all authentication types - that can be used. - - - - - Gets or sets number of bytes that a body can be. - - - - Used to determine the answer to a 100-continue request. - - - 0 = turned off. - - - - - - Gets current server. - - - Only valid when a request have been received and is being processed. - - - - - Gets or sets the maximum size of request body (in bytes) - - - - - Gets or sets server name. - - - Used in the "Server" header when serving requests. - - - - - Invoked just before a response is sent back to the client. - - - - - Invoked *after* the web server has tried to handled the request. - - - The event can be used to handle the request after all routes and modules - have tried to process the request. - - - - - Invoked *before* the web server has tried to handled the request. - - - Event can be used to load a session from a cookie or to force - authentication or anything other you might need t do before a request - is handled. - - - - - An error page have been requested. - - - - - Initializes a new instance of the class. - - - - - Used to build headers. - - - - - Add a parser - - Header that the parser is for. - Parser implementation - - Will replace any existing parser for the specified header. - - - - - Add all default (built-in) parsers. - - - Will not replace previously added parsers. - - - - - Create a header parser - - implementation. - - - Uses attribute to find which headers - the parser is for. - - Will not replace previously added parsers. - - - - - Parse a header. - - Name of header - Header value - Header. - Value is not a well formatted header value. - - - - Request sent to a HTTP server. - - - - - - Base interface for request and response. - - - - - Add a new header. - - - - - - - Add a new header. - - Header to add. - - - - Gets body stream. - - - - - Size of the body. MUST be specified before sending the header, - unless property Chunked is set to true. - - - - - Kind of content in the body - - Default is text/html - - - - Gets or sets encoding - - - - - Gets headers. - - - - - Get a header - - Type that it should be cast to - Name of header - Header if found and casted properly; otherwise null. - - - - Gets or sets connection header. - - - - - Gets cookies. - - - - - Gets all uploaded files. - - - - - Gets form parameters. - - - - - Gets or sets HTTP version. - - - - - Gets if request is an Ajax request. - - - - - Gets or sets HTTP method. - - - - - Gets query string and form parameters - - - - - Gets query string. - - - - - Gets requested URI. - - - - - Load resources from disk. - - - - - Loads resources from a specific location (such as assembly, hard drive etc). - - - - - Checks if a resource exists in the specified directory - - Uri path to resource - true if resource was found; otherwise false. - - - if (resources.Exists("/files/user/user.png")) - Debug.WriteLine("Resource exists."); - - - - - - Find all views in a folder/path. - - Absolute Uri path to files that should be found, can end with wild card. - Collection to add all view names to. - - - - Gets a resource. - - Uri path to resource. - Resource - Uri contains forbidden characters. - - - Resource resource = resources.Get("/files/user/user.png"); - - - - - - Default forbidden characters. - - - - - relative to absolute path mappings. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - Request URI path - Disk path - - File names should not be included in URI or path. - - - - new FileResources("/files/user/", "C:\\intetpub\\files\users\\"); - - - - - - Add a new resource mapping. - - Request URI path - Disk path - - File names should not be included in URI or path. - - - - resources.Add("/files/", "C:\\intetpub\\files\\"); - - - absolutePath is not found. - - - - check if source contains any of the chars. - - string to check - Characters to fined - - - - - Go through all mappings and find requested Uri. - - Uri to get local path for. - Path if found; otherwise null. - - - - Checks if a resource exists in the specified directory - - Uri path to resource - true if resource was found; otherwise false. - - - if (resources.Exists("/files/user/user.png")) - Debug.WriteLine("Resource exists."); - - - - - - Gets a resource. - - Uri path to resource. - Resource - Uri contains forbidden characters. - - - Resource resource = resources.Get("/files/user/user.png"); - - - - - - Find all views in a folder/path. - - Absolute Uri path to files that should be found, can end with wild card. - Collection to add all view names to. - Uri contains forbidden characters. - - Find(" - - - - - Gets or sets forbidden characters. - - - Used to revoke access to any system files. - - - - - Gets or sets absolute path on disk, including file name. - - - - - Gets or sets relative file path. - - - - - Gets or sets Uri path, excluding file name - - - - - Used to send a response back to the client. - - - - Writes a object into a stream. - - - Important! ResponseWriter do not throw any exceptions. Instead it just logs them and - let them die peacefully. This is since the response writer is used from - catch blocks here and there. - - - - - - Sends response using the specified context. - - The context. - The response. - - - - Converts and sends a string. - - - - Encoding used to transfer string - - - - Send a body to the client - - Context containing the stream to use. - Body to send - - - - Send all headers to the client - - Response containing call headers. - Content used to send headers. - - - - Decodes body stream. - - - - - Decode body stream - - Stream containing the content - Content type header - Stream encoding - Decoded data. - Body format is invalid for the specified content type. - Something unexpected failed. - - - - All content types that the decoder can parse. - - A collection of all content types that the decoder can handle. - - - - Decodes forms that have multiple sections. - - - http://www.faqs.org/rfcs/rfc1867.html - - - - - form-data - - - - - multipart/form-data - - - - - Decode body stream - - Stream containing the content - Content type header - Stream encoding - Decoded data. - Body format is invalid for the specified content type. - Something unexpected failed. - stream is null. - - - - All content types that the decoder can parse. - - A collection of all content types that the decoder can handle. - - - - Provides sessions. - - Type of session object - - Will always use files for sessions (utilizing the binary formatter), but can - also cache them in memory. - - If caching is enabled, it will only write sessions to disk every 20 seconds if they have - been accessed the last minute (to not keep writing dead sessions to disk). - - - - - - Initializes a new instance of the class. - - Session type must use [Serializable] attribute. - - - - Create a new session. - - - - - - Load session - - Id of session. - Session if found; otherwise null. - sessionId is null. - - - - Load session when a new request comes in. - - - - - - - Save a session to disk. - - Session to write to disk. - - You are responsible for writing sessions to disk if you are not using caching. - - - - - Start the session system and hook - - - - - - Stop session handling - - - - - Gets or sets session cookie name - - - - - Gets or sets cache - - - - - Gets current session. - - - - - Gets or sets number of seconds before a session expired. - - - A session have expired if nothing have accessed it for X seconds. This - class modifies the write time each time it's accessed. - - - - - Determines if cookie should be set in the response. - - - - - Invoked when a session have been changed and should be written to disc. - - - - - First line in a response have been received - - - - - Gets or sets motivation to why the status code was used. - - - - - Gets or sets message status code - - - - - Gets or sets sip protocol version used. - - - - - A request have been parsed successfully by the server. - - - - - Initializes a new instance of the class. - - Received request. - - - - Gets received request. - - - - - Provider returning user to be authenticated. - - - - - Lookups the specified user - - User name. - Typically web server domain name. - User if found; otherwise null. - - User name can basically be anything. For instance name entered by user when using - basic or digest authentication, or SID when using Windows authentication. - - - - - Gets the principal to use. - - Successfully authenticated user. - - - Invoked when a user have successfully been authenticated. - - - - - - - User information used during authentication process. - - - - - Gets or sets user name used during authentication. - - - - - Gets or sets unencrypted password. - - - Password as clear text. You could use instead if your passwords - are encrypted in the database. - - - - - Gets or sets HA1 hash. - - - - Digest authentication requires clear text passwords to work. If you - do not have that, you can store a HA1 hash in your database (which is part of - the Digest authentication process). - - - A HA1 hash is simply a Md5 encoded string: "UserName:Realm:Password". The quotes should - not be included. Realm is the currently requested Host (as in Request.Headers["host"]). - - - Leave the string as null if you are not using HA1 hashes. - - - - - - Used to get or set properties on objects. - - - This class should be a bit faster than the standard reflection. - - - - - Get cached type. - - Type to get/set properties in - Type to use - - - - Used to load/store sessions in the server. - - - - - Initializes a new instance of the class. - - Web server that the provider is for.. - Store to use. - - - - Initializes a new instance of the class. - - The server. - - Uses a file store. - - - - - Loads a session for all requests that got the session cookie. - - The sender. - The instance containing the event data. - - - - Gets current session - - Session if set, otherwise null. - - - - Gets or sets the session life time in minutes. - - The session life time. - - - - A session have been loaded. Use to access it. - - - - - Secure version of the HTTP listener. - - - - - Initializes a new instance of the class. - - Address to accept new connections on. - Port to accept connections on. - Certificate securing the connection. - - - - Create a new context - - Accepted socket - A new context. - - Factory is assigned by the on each incoming request. - - - - - Gets if listener is secure. - - - - - - Gets or sets SSL protocol. - - - - - Gets or sets if client certificate should be used. - - - - - Arguments used when more body bytes have come. - - - - - Initializes a new instance of the class. - - buffer that contains the received bytes. - offset in buffer where to start processing. - number of bytes from that should be parsed. - buffer is null. - - - - Initializes a new instance of the class. - - - - - Gets or sets buffer that contains the received bytes. - - - - - Gets or sets number of bytes from that should be parsed. - - - - - Gets or sets offset in buffer where to start processing. - - - - - HTTP Module - - - - - Process a request. - - Request information - What to do next. - - - - Something unexpected went wrong. - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Inner exception. - - - - File sent from remote end. - - - - - Gets or sets content type. - - - - - Gets or sets name in form. - - - - - Gets or sets name original file name - - - - - Gets or sets filename for locally stored file. - - - - - Parses Cookie header. - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Decodes URL encoded values. - - - - - - - Stream containing the content - Content type header - Stream encoding - Collection with all parameters. - Body format is invalid for the specified content type. - Failed to read all bytes from body stream. - - - - All content types that the decoder can parse. - - A collection of all content types that the decoder can handle. - - - - Base class for sessions. - - - Your class must be tagged with attribute to be able to use sessions. - - - - - The session have been changed and should be written to disk. - - - - - Session have been changed. - - - - - Gets or sets when session was accessed last - - - - - Gets current session. - - - - - Gets or sets session id. - - - - - Gets or sets when the session was last written to disk. - - - - - Parses and builds messages - - - The message factory takes care of building messages - from all end points. - - Since both message and packet protocols are used, the factory - hands out contexts to all end points. The context keeps a state - to be able to parse partial messages properly. - - - Each end point need to hand the context back to the message factory - when the client disconnects (or a message have been parsed). - - - - - - Initializes a new instance of the class. - - Factory used to create headers. - - - - Create a new message factory context. - - A new context. - - A context is used to parse messages from a specific endpoint. - - - - - Release a used factory context. - - - - - - A request have been received from one of the end points. - - - - - A response have been received from one of the end points. - - - - - Interface used to write to log files. - - - If you want to use the built in filtering mechanism, create a constructor - which takes one parameter, a . - - - - - Write an entry that helps when debugging code. - - Log message - - - - Write an entry that helps when debugging code. - - Log message - Thrown exception to log. - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - Thrown exception to log. - - - - Something went very wrong, application might not recover. - - Log message - - - - Something went very wrong, application might not recover. - - Log message - Thrown exception to log. - - - - Informational message, needed when helping customer to find a problem. - - Log message - - - - Informational message, needed when helping customer to find a problem. - - Log message - Thrown exception to log. - - - - Write a entry that helps when trying to find hard to find bugs. - - Log message - - - - Write a entry that helps when trying to find hard to find bugs. - - Log message - Thrown exception to log. - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - Thrown exception to log. - - - - cookie sent by the client/browser - - - - - - Constructor. - - cookie identifier - cookie content - id or content is null - id is empty - - - - Gets the cookie HTML representation. - - cookie string - - - - Gets the cookie identifier. - - - - - Gets value. - - - Set to null to remove cookie. - - - - - Arguments for . - - - - - Initializes a new instance of the class. - - The context. - - - - Gets or sets thrown exception - - - - - Gets or sets if error page was provided. - - - - - Gets requested resource. - - - - - Gets response to send - - - - - Implements HTTP Digest authentication. It's more secure than Basic auth since password is - encrypted with a "key" from the server. - - - Keep in mind that the password is encrypted with MD5. Use a combination of SSL and digest auth to be secure. - - - - - Authenticates requests - - - - - Authenticate request - - Authorization header send by web client - Realm to authenticate in, typically a domain name. - HTTP Verb used in the request. - User if authentication was successful; otherwise null. - - - - Create a authentication challenge. - - Realm that the user should authenticate in - A WWW-Authenticate header. - If realm is empty or null. - - - - Gets authenticator scheme - - - digest - - - - - Initializes a new instance of the class. - - Supplies users during authentication process. - - - - Used by test classes to be able to use hardcoded values - - - - - An authentication response have been received from the web browser. - Check if it's correct - - Contents from the Authorization header - Realm that should be authenticated - GET/POST/PUT/DELETE etc. - - Authentication object that is stored for the request. A user class or something like that. - - if authenticationHeader is invalid - If any of the parameters is empty or null. - - - - Encrypts parameters into a Digest string - - Realm that the user want to log into. - User logging in - Users password. - HTTP method. - Uri/domain that generated the login prompt. - Quality of Protection. - "Number used ONCE" - Hexadecimal request counter. - "Client Number used ONCE" - Digest encrypted string - - - - - - Md5 hex encoded "userName:realm:password", without the quotes. - Md5 hex encoded "method:uri", without the quotes - Quality of Protection - "Number used ONCE" - Hexadecimal request counter. - Client number used once - - - - - Create a authentication challenge. - - Realm that the user should authenticate in - A correct auth request. - If realm is empty or null. - - - - Gets the current nonce. - - - - - - Gets the Md5 hash bin hex2. - - To be hashed. - - - - - determines if the nonce is valid or has expired. - - nonce value (check wikipedia for info) - true if the nonce has not expired. - - - - Gets authentication scheme name - - - - - Gets authenticator scheme - - - - digest - - - - - Provides authentication in the web server. - - - To initiate authentication you just need to throw a Una - - - - - Add a authenticator. - - - - - - Authenticate request. - - - - - Requires that a AuthorizationHeader have been sent by the client. If not, - request one by sending a WWW-Authentication header (can be generated by the Challenge method). - - Authorization header was not found in the request. - Requested authentication scheme is not supported. - - - - Create a challenge header (WWW-authenticate) - - Response that the authentication header should be added to - Realm that the user should authenticate in - WWW-Authenticate header. - - - Scheme can currently be basic or digest. Basic is not very safe, but easier to use. - Digest is quite safe. - - - - Requested scheme is not supported. - - - - Creates a console logger. - - - - - Factory implementation used to create logs. - - - - - Create a new logger. - - Type that requested a logger. - Logger for the specified type; - - MUST ALWAYS return a logger. Return if no logging - should be used. - - - - - Initializes a new instance of the class. - - The filter. - - - - Create a new logger. - - Type that requested a logger. - Logger for the specified type; - - MUST ALWAYS return a logger. Return if no logging - should be used. - - - - - redirects from one URL to another. - - - - - Rules are used to perform operations before a request is being handled. - Rules can be used to create routing etc. - - - - - Process the incoming request. - - Request context information. - Processing result. - If any parameter is null. - - - - Initializes a new instance of the class. - - Absolute path (no server name) - Absolute path (no server name) - - server.Add(new RedirectRule("/", "/user/index")); - - - - - Initializes a new instance of the class. - - Absolute path (no server name) - Absolute path (no server name) - true if request should be redirected, false if the request URI should be replaced. - - server.Add(new RedirectRule("/", "/user/index")); - - - - - Process the incoming request. - - Request context. - Processing result. - If any parameter is null. - - - - Gets string to match request URI with. - - Is compared to request.Uri.AbsolutePath - - - - Gets whether the server should redirect the client instead of simply modifying the URI. - - - false means that the rule will replace - the current request URI with the new one from this class. - true means that a redirect response is sent to the client. - - - - - Gets where to redirect. - - - - - The Connection general-header field allows the sender to specify options - that are desired for that particular connection and MUST NOT be - communicated by proxies over further connections. - - - - HTTP/1.1 proxies MUST parse the Connection header field before a - message is forwarded and, for each connection-token in this field, - remove any header field(s) from the message with the same name as the - connection-token. Connection options are signaled by the presence of - a connection-token in the Connection header field, not by any - corresponding additional header field(s), since the additional header - field may not be sent if there are no parameters associated with that - connection option. - - Message headers listed in the Connection header MUST NOT include - end-to-end headers, such as Cache-Control. - - HTTP/1.1 defines the "close" connection option for the sender to - signal that the connection will be closed after completion of the - response. For example, - - Connection: close - - in either the request or the response header fields indicates that - the connection SHOULD NOT be considered `persistent' (section 8.1) - after the current request/response is complete. - - HTTP/1.1 applications that do not support persistent connections MUST - include the "close" connection option in every message. - - A system receiving an HTTP/1.0 (or lower-version) message that - includes a Connection header MUST, for each connection-token in this - field, remove and ignore any header field(s) from the message with - the same name as the connection-token. This protects against mistaken - forwarding of such header fields by pre-HTTP/1.1 proxies. See section - 19.6.2 in RFC2616. - - - - - - Header name - - - - - Default connection header for HTTP/1.0 - - - - - Default connection header for HTTP/1.1 - - - - - Initializes a new instance of the class. - - Connection type. - The parameters. - - - - Initializes a new instance of the class. - - The type. - - - - Returns data formatted as a HTTP header value. - - - A that represents the current . - - - - - Gets connection parameters. - - - - - Gets or sets connection type - - - - - Gets header name - - - - - Type of HTTP connection - - - - - Connection is closed after each request-response - - - - - Connection is kept alive for X seconds (unless another request have been made) - - - - - Requests message-body be sent with an encoding to be specified in the "Transfer-Encoding" header. - - - - - Helper for content types. - - - - - Flyweight design pattern implementation. - - Type of object. - - - - Initializes a new instance of the class. - - How large buffers to allocate. - - - - Get an object. - - Created object. - Will create one if queue is empty. - - - - Enqueues the specified buffer. - - Object to enqueue. - Buffer is is less than the minimum requirement. - - - - Used to create new objects. - - Type of objects to create. - Newly created object. - . - - - - A HTTP parser using delegates to which parsing methods. - - - - - Initializes a new instance of the class. - - - - - Parser method to copy all body bytes. - - - Needed since a TCP packet can contain multiple messages - after each other, or partial messages. - - - - Try to find a header name. - - - - - - Get header values. - - - Will also look for multi header values and automatically merge them to one line. - Content length is not a number. - - - - Toggle body bytes event. - - - - - - - - Raise the event, since we have successfully parsed a message and it's body. - - - - - First message line. - - Will always contain three elements. - Used to raise the or event - depending on the words in the array. - BadRequestException. - - - - Continue parsing a message - - Byte buffer containing bytes - Where to start the parsing - Number of bytes to parse - index where the parsing stopped. - Parsing failed. - - - - Parses the first line in a request/response. - - true if first line is well formatted; otherwise false. - Invalid request/response line. - - - - Reset parser to initial state. - - - - - Gets or sets current line number. - - - - - The request line has been parsed. - - - - - Response line has been parsed. - - - - - Parsed a header. - - - - - Received body bytes. - - - - - A message have been successfully parsed. - - - - - Used to be able to quickly swap parser method. - - - - - - Get or create components used in the web server framework - - - - - - - - Get or create a type. - - Type to create - Created type. - - Gets or creates types in the framework. - Check for more information on which - types the factory should contain. - - - - - Used to create all key types in the HTTP server. - - - Should have factory methods at least for the following types: - , , - , , - , , - , , - . - - Check the default implementations to see which constructor - parameters you will get. - - - HttpFactory.Add(typeof(IRequest), (type, args) => new MyRequest((string)args[0])); - - - - - - Initializes a new instance of the class. - - - - - Add a factory method for a type. - - Type to create - Method creating the type. - - - - Used to - - - - - - - Setup our singleton. - - - - - - We want to use a singleton, but we also want to be able - to let the developer to setup his own header factory. - Therefore we use this method to create our own factory only if the user - have not specified one. - - - - - Small method to create a message factory singleton and replace then default delegate method. - - - - - - - - Create a type. - - Type to create - Created type. - - - - Gets http factory for the current listener. - - - - - Delegate used to create a certain type - - Created type. - - Method must never fail. - - - - - Used to define which headers a parse is for. - - - - - Initializes a new instance of the class. - - Name of the header. - - - - Gets name of header that this parser is for. - - - - - Parses "Date" header. - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Authorization response - - - - A user agent that wishes to authenticate itself with a server-- - usually, but not necessarily, after receiving a 401 response--does - so by including an Authorization request-header field with the - request. The Authorization field value consists of credentials - containing the authentication information of the user agent for - the realm of the resource being requested. - - - Authorization = "Authorization" ":" credentials - - - HTTP access authentication is described in "HTTP Authentication: - Basic and Digest Access Authentication" [43]. If a request is - authenticated and a realm specified, the same credentials SHOULD - be valid for all other requests within this realm (assuming that - the authentication scheme itself does not require otherwise, such - as credentials that vary according to a challenge value or using - synchronized clocks). - When a shared cache (see section 13.7) receives a request - containing an Authorization field, it MUST NOT return the - corresponding response as a reply to any other request, unless one - of the following specific exceptions holds: - - - - If the response includes the "s-maxage" cache-control - directive, the cache MAY use that response in replying to a - subsequent request. But (if the specified maximum age has - passed) a proxy cache MUST first revalidate it with the origin - server, using the request-headers from the new request to allow - the origin server to authenticate the new request. (This is the - defined behavior for s-maxage.) If the response includes "s- - maxage=0", the proxy MUST always revalidate it before re-using - it. - - If the response includes the "must-revalidate" cache-control - directive, the cache MAY use that response in replying to a - subsequent request. But if the response is stale, all caches - MUST first revalidate it with the origin server, using the - request-headers from the new request to allow the origin server - to authenticate the new request. - - If the response includes the "public" cache-control directive, - it MAY be returned in reply to any subsequent request. - - - - - - - Name constant - - - - - Gets or sets authentication data. - - - - - Gets or sets authentication protocol. - - - - - Gets name of header. - - - - - User needs to authenticate. - - - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Inner exception. - - - - A response have been received. - - - - - Initializes a new instance of the class. - - The response. - - - - Gets or sets response. - - - - - Creates a single message for one of the end points. - - - The factory is - - - - - Initializes a new instance of the class. - - The MSG factory. - The factory. - The parser. - - - - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - - 2 - - - - Received a header from parser - - - - - - - Will continue the parsing until nothing more can be parsed. - - buffer to parse - where to start in the buffer - number of bytes to process. - Position where parser stopped parsing. - Parsing failed. - - - - Reset parser. - - - Something failed, reset parser so it can start on a new request. - - - - - A request have been successfully parsed. - - - - - A response have been successfully parsed. - - - - - Client asks if he may continue. - - - If the body is too large or anything like that you should respond . - - - - - Used to notify about 100-continue header. - - - - - Initializes a new instance of the class. - - request that want to continue. - - - - Gets request that want to continue - - - - - Default log filter implementation. - - - - - Determines which classes can log - - - - - Checks if the specified type can send - log entries at the specified level. - - Log level - Type that want to write a log entry. - true if logging is allowed; otherwise false. - - - - Add a name space filter. - - Name space to add filter for. - Minimum log level required. - - - // Parsing can only add error and fatal messages - AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); - AddType(typeof(SipParser), LogLevel.Error); - - // Transport layer can only log warnings, errors and fatal messages - AddNamespace("SipSharp.Transports.*", LogLevel.Warning); - - - - - - Used to specify standard filter rules - - - Parser can only display errors. Transports only warnings. - - - - - Add filter for a type - - Type to add filter for. - Minimum log level required. - - - // Parsing can only add error and fatal messages - AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); - AddType(typeof(SipParser), LogLevel.Error); - - // Transport layer can only log warnings, errors and fatal messages - AddNamespace("SipSharp.Transports.*", LogLevel.Warning); - - - - - - Add filter for a type - - Type to add filter for. - Minimum log level required. - - - // Parsing can only add error and fatal messages - AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); - AddType("SipSharp.Messages.MessageFactory", LogLevel.Error); - - // Transport layer can only log warnings, errors and fatal messages - AddNamespace("SipSharp.Transports.*", LogLevel.Warning); - - - Type could not be identified. - - - - Checks if the specified type can send - log entries at the specified level. - - Log level - Type that want to write a log entry. - true if logging is allowed; otherwise false. - - - No filters = everything logged. = no logs. Don't use a rule with '*' or '.*' - - - - User have specified a wild card filter. - - - Wild card filters are used to log a name space and - all it's children name spaces. - - - - - Result of processing. - - - - - Continue with the next handler - - - - - No more handlers can process the request. - - - The server will process the response object and - generate a HTTP response from it. - - - - - Response have been sent back by the handler. - - - This option should only be used if you are streaming - something or sending back a custom result. The server will - not process the response object or send anything back - to the client. - - - - - Used to store all headers that that aren't recognized. - - - - - Initializes a new instance of the class. - - The name. - The value. - - - - Gets or sets value - - - - - Gets header name - - - - - Parses . - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Collection of parameters - - - - - Get a parameter. - - - - - - - Add a query string parameter. - - Parameter name - Value - - - - Checks if the specified parameter exists - - Parameter name. - true if found; otherwise false; - - - - Gets number of parameters. - - - - - Gets last value of an parameter. - - Parameter name - String if found; otherwise null. - - - - Parameter in - - - - - Gets *last* value. - - - Parameters can have multiple values. This property will always get the last value in the list. - - String if any value exist; otherwise null. - - - - Gets or sets name. - - - - - Gets a list of all values. - - - - - A parameter in . - - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Gets last value. - - - Parameters can have multiple values. This property will always get the last value in the list. - - String if any value exist; otherwise null. - - - - Gets or sets name. - - - - - Gets a list of all values. - - - - - Used when the request line have been successfully parsed. - - - - - Initializes a new instance of the class. - - The HTTP method. - The URI path. - The HTTP version. - - - - Initializes a new instance of the class. - - - - - Gets or sets HTTP method. - - - Should be one of the methods declared in . - - - - - Gets or sets requested URI path. - - - - - Gets or sets the version of the SIP protocol that the client want to use. - - - - - Content-type - - - - - Header name. - - - - - Initializes a new instance of the class. - - Type of the content. - Value parameters. - - - - Initializes a new instance of the class. - - Type of the content. - - - - Returns data formatted as a HTTP header value. - - - A that represents the current . - - - - - Gets all parameters. - - - - - Gets content type. - - - - - Gets header name - - - - - Requested resource may not be accessed. - - - Normally thrown after an authentication attempt have failed too many times. - - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Inner exception. - - - - Stream-based multipart handling. - - In this incarnation deals with an HttpInputStream as we are now using - IntPtr-based streams instead of byte []. In the future, we will also - send uploads above a certain threshold into the disk (to implement - limit-less HttpInputFiles). - - - Taken from HttpRequest in mono (http://www.mono-project.com) - - - - - Client X.509 certificate, X.509 chain, and any SSL policy errors encountered - during the SSL stream creation - - - - - Initializes a new instance of the class. - - The certificate. - Client security certificate chain. - Any SSL policy errors encountered during the SSL stream creation. - - - - Client security certificate - - - - - Client security certificate chain - - - - - Any SSL policy errors encountered during the SSL stream creation - - - - - Credits and description: http://theinstructionlimit.com/?p=76 - - - Converted to .Net 2.0 - - - - - Session in the system - - - - - Gets or sets session id. - - - - - Factory creating null logger. - - - - - Initializes a new instance of the class. - - - - - Create a new logger. - - Type that requested a logger. - Logger for the specified type; - - MUST ALWAYS return a logger. Return if no logging - should be used. - - - - - Logger instance. - - - - - Provides resources. - - - - - Used to access resources. - - - - - Add a new resource loader. - - Provider to add. - Manager have been started. - - - - Check if a resource exists. - - Uri to check - true if found; otherwise false. - - - if (manager.Exists("/views/user/view.haml")) - return true - - - - - - Get a resource. - - Uri path to resource. - Resource if found; otherwise null. - - - Resource resource = manager.Get("/views/user/view.haml"); - - - - - - Start manager. - - - - - Gets number of resource providers - - - - - Get all view names from a folder. - - Path to find views in. - A collection of view names (without path). - - - - Add a new resource loader. - - Provider to add. - Manager have been started. - - - - Start manager. - - - - - Check if a resource exists. - - Uri to check - true if found; otherwise false. - - - if (manager.Exists("/views/user/view.haml")) - return true - - - - - - Get a resource. - - Uri path to resource. - Resource if found; otherwise null. - - - Resource resource = manager.Get("/views/user/view.haml"); - - - - - - Gets number of resource providers - - - - - Loads resources that are embedded in assemblies. - - - No locks used internally since all mappings are loaded during start up. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - Path (Uri) requested by clients - Assembly that the resources exist in - Name space that the resources exist in - - - - Add a specific resource. - - Path (Uri) requested by clients - Assembly that the resources exist in - Name space to root folder under (all name spaces below the specified one are considered as folders) - Name space and name of resource. - - - Add("/", Assembly.GetExecutingAssembly(), "MyApplication.Files", "Myapplication.Files.Images.MyImage.png"); - - - - - - Add resources. - - Path (Uri) requested by clients - Assembly that the resources exist in - Name of resource, including name space. - true if file was found (and has not previously been added); otherwise false. - - - - - - Add resources in a specific path (will not work with sub folders) - - Path (Uri) requested by clients - Assembly that the resources exist in - Name space to root folder under which all name spaces exists in, - true if any files was found; otherwise false. - - - Adds all views in the specified folder. Sub folders are not supported since it's hard to determine - with parts are the path and witch parts are the filename. Use to get support - for sub folders. - - - - - Add("/user/", typeof(MyController).Assembly, "YourProject.Users.Views"); - - - - - - Add resources in a folder and it's sub folder - - - - - - This method is not going to map files but keep the mapping and - try to look up views every time they are requested. This is the method - to use to add a resource folder that has sub folders. - - - - - - Tries to load file by using previously added paths. - - Uri path including file name - - - - - Checks if a resource exists in the specified directory - - Uri path to resource - true if resource was found; otherwise false. - - - if (resources.Exists("/files/user/user.png")) - Debug.WriteLine("Resource exists."); - - - - - - Load a resource. - - Uri of resource. - Resource if found and loaded; otherwise null. - - - - Find all views in a folder/path. - - Uri path - Collection to add all view names to. - - - - Loads all files in a resource directory - - - - - - Gets or sets assembly that the resource exists in. - - - - - Gets or sets resource name. - - - - - Gets or sets full name space path to resource. - - - - - Gets or sets if this file is for a certain content type. - - - - - Gets or sets full "virtual" Uri path, excluding file name. - - - - - Gets or sets assembly - - - - - Gets or sets name space root. - - - - - Gets or sets uri path. - - - - - A list of request cookies. - - - - - Let's copy all the cookies. - - value from cookie header. - - - - Initializes a new instance of the class. - - - - - Adds a cookie in the collection. - - cookie to add - cookie is null - Name must be specified. - - - - Remove all cookies. - - - - - Remove a cookie from the collection. - - Name of cookie. - - - - Gets a collection enumerator on the cookie list. - - collection enumerator - - - - Returns an enumerator that iterates through the collection. - - - - A that can be used to iterate through the collection. - - 1 - - - - Gets the count of cookies in the collection. - - - - - Gets the cookie of a given identifier (null if not existing). - - - - - Collection of headers. - - - - - Collection of headers. - - - - - Gets a header - - header name. - header if found; otherwise null. - - - - Initializes a new instance of the class. - - Factory used to created headers. - - - - Adds a header - - - Will replace any existing header with the same name. - - header to add - header is null. - Header name cannot be null. - - - - Add a header. - - Header name - Header value - - Will try to parse the header and create a object. - - Header value is not correctly formatted. - name or value is null. - - - - Add a header. - - Header name - Header value - - Will try to parse the header and create a object. - - name or value is null. - - - - Get a header - - Type that it should be cast to - Name of header - Header if found and casted properly; otherwise null. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Gets a header - - header name. - header if found; otherwise null. - - - - Header for "Date" and "If-Modified-Since" - - - - The field value is an HTTP-date, as described in section 3.3.1 in RFC2616; - it MUST be sent in RFC 1123 [8]-date format. An example is - - Date: Tue, 15 Nov 1994 08:12:31 GMT - - Origin servers MUST include a Date header field in all - responses, except in these cases: - - If the response status code is 100 (Continue) or 101 (Switching - Protocols), the response MAY include a Date header field, at the server's - option. - If the response status code conveys a server error, e.g. 500 - (Internal Server Error) or 503 (Service Unavailable), and it is inconvenient - or impossible to generate a valid Date. - If the server does not have a clock that can provide a - reasonable approximation of the current time, its responses MUST NOT include - a Date header field. In this case, the rules in section 14.18.1 in RFC2616 - MUST be followed. - - - A received message that does not have a Date header field MUST - be assigned one by the recipient if the message will be cached by that - recipient or gatewayed via a protocol which requires a Date. An HTTP - implementation without a clock MUST NOT cache responses without revalidating - them on every use. An HTTP cache, especially a shared cache, SHOULD use a - mechanism, such as NTP [28], to synchronize its clock with a reliable - external standard. - Clients SHOULD only send a Date header field in messages that - include an entity-body, as in the case of the PUT and POST requests, and - even then it is optional. A client without a clock MUST NOT send a Date - header field in a request. - The HTTP-date sent in a Date header SHOULD NOT represent a date - and time subsequent to the generation of the message. It SHOULD represent - the best available approximation of the date and time of message generation, - unless the implementation has no means of generating a reasonably accurate - date and time. In theory, the date ought to represent the moment just before - the entity is generated. In practice, the date can be generated at any time - during the message origination without affecting its semantic value. - - - - - - Header name - - - - - Initializes a new instance of the class. - - Header name. - Name must not be empty. - - - - Initializes a new instance of the class. - - Header name. - Universal time. - - - - Returns data formatted as a HTTP header value. - - - A that represents the current . - - - - - Gets or sets date time. - - Should be in UTC. - - - - Gets header name - - - - - Type cached for fast property value modifications. - - - - - Get a property value. - - Instance to get value from. - Name of property. - Property value. - - - - Assign a value, try to convert it if it's not the same type as the property type. - - Object containing the property - Name of property - Value to convert and assign - Failed to find property. - Could not convert value type to property type. - - - - Assign value to a property - - Object containing the property - Name of property - Value to assign, must be of the same type as the property. - Failed to find property. - - - - Used to cache property information - - - - - Gets the property. - - The name. - - Failed to find property. - - - InvalidCastException. - - - - Get a property value. - - Instance to get value from. - Name of property. - Property value. - - - - Assign a value, try to convert it if it's not the same type as the property type. - - Object containing the property - Name of property - Value to convert and assign - Failed to find property. - Could not convert value type to property type. - - - - Assign value to a property - - Object containing the property - Name of property - Value to assign, must be of the same type as the property. - Failed to find property. - - - - Gets or sets member info - - - - - Gets or sets member type - - - - - Base interface to read string tokens from different sources. - - - - - Assign a new buffer - - Buffer to process. - Where to start process buffer - Buffer length - - - - Assign a new buffer - - Buffer to process - - - - Consume current character. - - - - - Consume specified characters - - One or more characters. - - - - Consumes horizontal white spaces (space and tab). - - - - - Consume horizontal white spaces and the specified character. - - Extra character to consume - - - - Checks if one of the remaining bytes are a specified character. - - Character to find. - true if found; otherwise false. - - - - Read a character. - - Character if not EOF; otherwise null. - - - - Get a text line. - - - Will merge multiline headers. - - - - Read quoted string - - string if current character (in buffer) is a quote; otherwise null. - - - - Read until end of string, or to one of the delimiters are found. - - characters to stop at - A string (can be ). - - Will not consume the delimiter. - - - - - Read until end of string, or to one of the delimiters are found. - - A string (can be ). - - Will not consume the delimiter. - - - - - Read to end of buffer, or until specified delimiter is found. - - Delimiter to find. - A string (can be ). - - Will not consume the delimiter. - - - - - Will read until specified delimiter is found. - - Character to stop at. - A string if the delimiter was found; otherwise null. - - Will trim away spaces and tabs from the end. - Will not consume the delimiter. - - - - - Read until one of the delimiters are found. - - characters to stop at - A string if one of the delimiters was found; otherwise null. - - Will trim away spaces and tabs from the end. - Will not consume the delimiter. - - - - - Read until a horizontal white space occurs. - - A string if a white space was found; otherwise null. - - - - Gets current character - - if end of buffer. - - - - Gets if end of buffer have been reached - - - - - Gets if more bytes can be processed. - - - - - Gets or sets current position in buffer. - - - THINK before you manually change the position since it can blow up - the whole parsing in your face. - - - - - Gets total length of buffer. - - - - - Gets or sets line number. - - - - - Gets next character - - if end of buffer. - - - - Gets number of bytes left. - - - - - Factory is used to create new logs in the system. - - - - - Assigns log factory being used. - - The log factory. - A factory have already been assigned. - - - - Create a new logger. - - Type that requested a logger. - Logger for the specified type; - - - - Component that should be registered in the container. - - - Register using all interfaces that is specified in this assembly. - - - - - Used to authenticate users - - - Authentication is requested by throwing - - - - - Request implementation. - - - - - Initializes a new instance of the class. - - The method. - The path. - The version. - - - - Get a header - - Type that it should be cast to - Name of header - Header if found and casted properly; otherwise null. - - - - Add a new header. - - - - - - - Add a new header. - - Header to add. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Gets a header. - - - - - - - Gets request URI. - - - - - Gets cookies. - - - - - Gets all uploaded files. - - - - - Gets query string and form parameters - - - - - Gets form parameters. - - - - - Gets query string. - - - - - Gets if request is an Ajax request. - - - - - Gets or sets connection header. - - - - - Gets or sets HTTP version. - - - - - Gets or sets HTTP method. - - - - - Gets requested URI. - - - - - Kind of content in the body - - Default is text/html - - - - Gets or sets encoding - - - - - Gets headers. - - - - - Gets body stream. - - - - - Size of the body. MUST be specified before sending the header, - unless property Chunked is set to true. - - - Any specifically assigned value or Body stream length. - - - - - Event arguments used when a new header have been parsed. - - - - - Initializes a new instance of the class. - - Name of header. - Header value. - Name cannot be empty - value is null. - - - - Initializes a new instance of the class. - - - - - Gets or sets header name. - - - - - Gets or sets header value. - - - - - Collection of parameters. - - - or is not used since each parameter can - have multiple values. - - - - - Initializes a new instance of the class. - - Collections to merge. - - Later collections will overwrite parameters from earlier collections. - - - - - Initializes a new instance of the class. - - - - - Get a list of string arrays. - - - - - - Get parameters - - Sub array (text array) - - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Get a parameter. - - - - - - - Add a query string parameter. - - Parameter name - Value - - - - Checks if the specified parameter exists - - Parameter name. - true if found; otherwise false; - - - - Gets number of parameters. - - - - - Gets last value of an parameter. - - Parameter name - String if found; otherwise null. - - - - Parses . - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Parses numerical values - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Parses . - - - - - Parse a header - - Name of header. - Reader containing value. - HTTP Header - Header value is not of the expected format. - - - - Request couldn't be parsed successfully. - - - - - Initializes a new instance of the class. - - Exception description. - - - - Initializes a new instance of the class. - - Exception description. - Exception description. - - - - Implements basic authentication scheme. - - - - - Create a response that can be sent in the WWW-Authenticate header. - - Realm that the user should authenticate in - Not used by basic authentication - A WWW-Authenticate header. - Argument is null. - - - - An authentication response have been received from the web browser. - Check if it's correct - - Authorization header - Realm that should be authenticated - GET/POST/PUT/DELETE etc. - Authentication object that is stored for the request. A user class or something like that. - if authenticationHeader is invalid - If any of the paramters is empty or null. - - - - Gets authenticator scheme - - - - digest - - - - - Reads strings from a byte array. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - Encoding to use when converting byte array to strings. - - - - Initializes a new instance of the class. - - Buffer to read from. - Encoding to use when converting byte array to strings. - - - - Assign a new buffer - - Buffer to process. - Where to start process buffer - Buffer length - Buffer needs to be a byte array - - - - Assign a new buffer - - Buffer to process - Buffer needs to be a byte array - - - - Consume current character. - - - - - Get a text line. - - - Will merge multi line headers. - - - - Read quoted string - - string if current character (in buffer) is a quote; otherwise null. - - - - Read until end of string, or to one of the delimiters are found. - - characters to stop at - - A string (can be ). - - - Will not consume the delimiter. - - InvalidOperationException. - - - - Read until end of string, or to one of the delimiters are found. - - A string (can be ). - - Will not consume the delimiter. - - - - - Read to end of buffer, or until specified delimiter is found. - - Delimiter to find. - - A string (can be ). - - - Will not consume the delimiter. - - InvalidOperationException. - - - - Consume specified characters - - One or more characters. - - - - Consumes horizontal white spaces (space and tab). - - - - - Consume horizontal white spaces and the specified character. - - Extra character to consume - - - - Read a character. - - - Character if not EOF; otherwise null. - - - - - Will read until specified delimiter is found. - - Character to stop at. - - A string if the delimiter was found; otherwise null. - - - Will trim away spaces and tabs from the end. - InvalidOperationException. - - - - Read until one of the delimiters are found. - - characters to stop at - - A string if one of the delimiters was found; otherwise null. - - - Will not consume the delimiter. - - InvalidOperationException. - - - - Read until a horizontal white space occurs. - - A string if a white space was found; otherwise null. - - - - Checks if one of the remaining bytes are a specified character. - - Character to find. - - true if found; otherwise false. - - - - - Gets or sets line number. - - - - - Gets if end of buffer have been reached - - - - - - Gets if more bytes can be processed. - - - - - - Gets next character - - if end of buffer. - - - - Gets current character - - if end of buffer. - - - - Gets or sets current position in buffer. - - - THINK before you manually change the position since it can blow up - the whole parsing in your face. - - - - - Gets total length of buffer. - - - - - - Gets number of bytes left. - - - - - Response to a request. - - - - - Redirect user. - - Where to redirect to. - - Any modifications after a redirect will be ignored. - - - - - Gets connection type. - - - - - Gets cookies. - - - - - Gets HTTP version. - - - Default is HTTP/1.1 - - - - - Information about why a specific status code was used. - - - - - Status code that is sent to the client. - - Default is - - - - Gets or sets content type - - - - - Request context - - - Contains information about a HTTP request and where it came from. - - - - - Gets or sets http context. - - - - - Gets or sets http request. - - - - - Gets or sets http response. - - - - - Contains numerical value. - - - - - Initializes a new instance of the class. - - The name. - The value. - - - - Returns data formatted as a HTTP header value. - - - A that represents the current . - - - - - Gets value - - - - - Gets header name - - - - - Form parameters where form string arrays have been converted to real arrays. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class. - - The name. - The value. - - - - Initializes a new instance of the class. - - Parse parameters from the this collection. - - - - Get a parameter. - - - - - - - Add a parameter - - Name of parameter, can contain a string array. - Value - - - ArrayParameterCollection array = new ArrayParameterCollection(); - array.Add("user[FirstName]", "Jonas"); - array.Add("user[FirstName]", "Arne"); - string firstName = array["user"]["FirstName"].Value; // "Arne" is returned - foreach (string value in array["user"]["FirstName"]) - Console.WriteLine(value); // each name is displayed. - - - - - - Checks if the specified parameter exists - - Parameter name. - true if found; otherwise false; - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Gets first value of an item. - - - String if found; otherwise null. - - - - Gets number of parameters. - - - - - Gets last value of an parameter. - - Parameter name - String if found; otherwise null. - - - - Assign properties from HTTP parameters. - - - - - Used to filter out properties. - - Filter handler. - Handler have already been set. - - - - Assign properties in the specified object. - - Object to fill. - Contains all parameters that should be assigned to the properties. - Properties was not found or value could not be converted. - Any parameter is null. - - - - Used to be able to filter properties - - Model having it's properties assigned - Property about to be assigned - Value to assign - true if value can be set; otherwise false. - - - - Failed to assign properties. - - - - - Initializes a new instance of the class. - - The property errors. - - - - Gets all errors during assignment. - - - Dictionary key is property name. - - - - - Used to read from a string object. - - - - - Initializes a new instance of the class. - - Buffer to process. - - - - Initializes a new instance of the class. - - - - - Assign a new buffer - - Buffer to process. - Where to start process buffer - Buffer length - MUST be of type . - buffer needs to be of type string - - - - Assign a new buffer - - Buffer to process - MUST be of type . - buffer needs to be of type string - - - - Consume current character. - - - - - Get a text line. - - - Will merge multiline headers. - - - - Read quoted string - - string if current character (in buffer) is a quote; otherwise null. - - - - Read until end of string, or to one of the delimiters are found. - - characters to stop at - A string (can be ). - InvalidOperationException. - - - - Read until end of string, or to one of the delimiters are found. - - A string (can be ). - - Will not consume the delimiter. - - - - - Read to end of buffer, or until specified delimiter is found. - - Delimiter to find. - A string (can be ). - InvalidOperationException. - - - - Consume specified characters - - One or more characters. - - - - Consumes horizontal white spaces (space and tab). - - - - - Read a character. - - - Character if not EOF; otherwise null. - - - - - Will read until specified delimiter is found. - - Character to stop at. - - A string if the delimiter was found; otherwise null. - - - Will trim away spaces and tabs from the end. - Will not consume the delimiter. - - InvalidOperationException. - - - - Read until one of the delimiters are found. - - characters to stop at - - A string if one of the delimiters was found; otherwise null. - - - Will not consume the delimiter. - - InvalidOperationException. - - - - Read until a horizontal white space occurs (or end, or end of line). - - - A string if a white space was found; otherwise null. - - - - - Consume horizontal white spaces and the specified character. - - Extra character to consume - - - - Checks if one of the remaining bytes are a specified character. - - Character to find. - - true if found; otherwise false. - - - - - Gets or sets line number. - - - - - Gets if end of buffer have been reached - - - - - - Gets if more bytes can be processed. - - - - - - Gets next character - - if end of buffer. - - - - Gets current character - - if end of buffer. - - - - Gets or sets current position in buffer. - - - THINK before you manually change the position since it can blow up - the whole parsing in your face. - - - - - Gets total length of buffer. - - - - - - Gets number of bytes left. - - - - - Default log writer, writes everything to void (nowhere). - - - - - - The logging instance. - - - - - Write an entry that helps when debugging code. - - Log message - - - - Write an entry that helps when debugging code. - - Log message - Thrown exception to log. - - - - Write a entry needed when following through code during hard to find bugs. - - Log message - - - - Write a entry that helps when trying to find hard to find bugs. - - Log message - Thrown exception to log. - - - - Informational message, needed when helping customer to find a problem. - - Log message - - - - Informational message, needed when helping customer to find a problem. - - Log message - Thrown exception to log. - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - Thrown exception to log. - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - Thrown exception to log. - - - - Something went very wrong, application might not recover. - - Log message - - - - Something went very wrong, application might not recover. - - Log message - Thrown exception to log. - - - - Priority for log entries - - - - - - Very detailed logs to be able to follow the flow of the program. - - - - - Logs to help debug errors in the application - - - - - Information to be able to keep track of state changes etc. - - - - - Something did not go as we expected, but it's no problem. - - - - - Something that should not fail failed, but we can still keep - on going. - - - - - Something failed, and we cannot handle it properly. - - - - - This class writes to the console. - - - It colors the output depending on the log level - and includes a 3-level stack trace (in debug mode) - - - - - - Initializes a new instance of the class. - - Type being logged. - Log filter. - - - - Get color for the specified log level - - Level for the log entry - A for the level - - - - Write an entry - - Importance of the log message - The message. - - - - Write an entry that helps when debugging code. - - Log message - - - - Write an entry that helps when debugging code. - - Log message - Thrown exception to log. - - - - Write a entry needed when following through code during hard to find bugs. - - Log message - - - - Write a entry that helps when trying to find hard to find bugs. - - Log message - Thrown exception to log. - - - - Informational message, needed when helping customer to find a problem. - - Log message - - - - Informational message, needed when helping customer to find a problem. - - Log message - Thrown exception to log. - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - - - - Something is not as we expect, but the code can continue to run without any changes. - - Log message - Thrown exception to log. - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - - - - Something went wrong, but the application do not need to die. The current thread/request - cannot continue as expected. - - Log message - Thrown exception to log. - - - - Something went very wrong, application might not recover. - - Log message - - - - Something went very wrong, application might not recover. - - Log message - Thrown exception to log. - - - - Gets or sets type that the logger is for - - - - - A HTTP context - - - - - - - - Context that received a HTTP request. - - - - - Disconnect context. - - - - - Gets if current context is using a secure connection. - - - - - Gets logger. - - - - - Gets remote end point - - - - - Gets stream used to send/receive data to/from remote end point. - - - - The stream can be any type of stream, do not assume that it's a network - stream. For instance, it can be a or a ZipStream. - - - - - - Gets the currently handled request - - The request. - - - - Gets the response that is going to be sent back - - The response. - - - - Initializes a new instance of the class. - - Socket received from HTTP listener. - Context used to parse incoming messages. - - - - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - - 2 - - - - Disconnect context. - - - - - Close and release socket. - - - - - Create stream used to send and receive bytes from the socket. - - Socket to wrap - Stream - Stream could not be created. - - - - Interpret incoming data. - - - - - - A request was received from the parser. - - - - - - - Parse all complete requests in buffer. - - - offset in buffer where parsing stopped. - Parsing failed. - - - - Start content. - - A socket operation failed. - Reading from stream failed. - - - - Gets currently executing HTTP context. - - - - - Gets or sets description - - - - - gets factory used to build request objects - - - - - Gets socket - - - - - Gets remove end point - - - - - Gets network stream. - - - - - Gets the currently handled request - - The request. - - - - Gets the response that is going to be sent back - - The response. - - - - Gets logger. - - - - - Gets if current context is using a secure connection. - - - - - Triggered for all requests in the server (after the response have been sent) - - - - - Triggered for current request (after the response have been sent) - - - - - A new request have been received. - - - - - A new request have been received (invoked for ALL requests) - - - - - Client have been disconnected. - - - - - Client asks if he may continue. - - - If the body is too large or anything like that you should respond . - - - - - Initializes a new instance of the class. - - SSL protocol to use. - The socket. - The context. - Server certificate to use. - - - - Create stream used to send and receive bytes from the socket. - - Socket to wrap - Stream - Stream could not be created. - - - - Gets or sets client certificate. - - - - - Gets used protocol. - - - - - Gets or sets if client certificate should be used instead of server certificate. - - - - - Resource information. - - - Used by content providers to be able to get information - on resources (views, files etc). - - - - - Gets or sets date when resource was modified. - - - if not used. - - - Should always be universal time. - - - - - Gets or sets resource stream. - - - - - Contains parameters for HTTP headers. - - - - - Add a parameter - - name - value - - Existing parameter with the same name will be replaced. - - - - - Parse parameters. - - Parser containing buffer to parse. - A collection with all parameters (or just a empty collection). - Expected a value after equal sign. - - - - Parse parameters. - - Parser containing buffer to parse. - Parameter delimiter - A collection with all parameters (or just a empty collection). - Expected a value after equal sign. - - - - Returns a that represents the current . - - - A that represents the current . - - - - - Gets or sets a value - - parameter name - value if found; otherwise null. - - - - Create a HTTP response object. - - - - - Initializes a new instance of the class. - - HTTP Version. - HTTP status code. - Why the status code was selected. - Version must start with 'HTTP/' - - - - Initializes a new instance of the class. - - Context that the response will be sent through. - Request that the response is for. - Version must start with 'HTTP/' - - - - Redirect user. - - Where to redirect to. - - Any modifications after a redirect will be ignored. - - - - - Add a new header. - - - - - - - Add a new header. - - Header to add. - - - - Returns an enumerator that iterates through the collection. - - - A that can be used to iterate through the collection. - - 1 - - - - Returns an enumerator that iterates through a collection. - - - An object that can be used to iterate through the collection. - - 2 - - - - Gets a header. - - - - - - - Gets connection type. - - - - - Status code that is sent to the client. - - Default is - - - - Gets HTTP version. - - - Default is HTTP/1.1 - - - - - Information about why a specific status code was used. - - - - - Size of the body. MUST be specified before sending the header, - unless property Chunked is set to true. - - - Any specifically assigned value or Body stream length. - - - - - Kind of content in the body - - Default is text/html - - - - Gets or sets encoding - - - - - Gets cookies. - - - - - Gets body stream. - - - - - Gets headers. - - - - - A request have been received. - - - - - Initializes a new instance of the class. - - The request. - End point that the request was received from. - - - - End point that the message was received from. - - - - - Received request. - - - - - Class to make dynamic binding of redirects. Instead of having to specify a number of similar redirect rules - a regular expression can be used to identify redirect URLs and their targets. - - - [a-z0-9]+)", "/users/${target}/?find=true", RegexOptions.IgnoreCase) - ]]> - - - - - Initializes a new instance of the class. - - Expression to match URL - Expression to generate URL - - [a-zA-Z0-9]+)", "/user/${first}")); - Result of ie. /employee1 will then be /user/employee1 - ]]> - - - - - Initializes a new instance of the class. - - Expression to match URL - Expression to generate URL - Regular expression options to use, can be null - - [a-zA-Z0-9]+)", "/user/{first}", RegexOptions.IgnoreCase)); - Result of ie. /employee1 will then be /user/employee1 - ]]> - - - - - Initializes a new instance of the class. - - Expression to match URL - Expression to generate URL - Regular expression options to apply - true if request should be redirected, false if the request URI should be replaced. - - [a-zA-Z0-9]+)", "/user/${first}", RegexOptions.None)); - Result of ie. /employee1 will then be /user/employee1 - ]]> - - Argument is null. - - - - - Process the incoming request. - - Request context. - Processing result. - If any parameter is null. - - - - cookie being sent back to the browser. - - - - - - Constructor. - - cookie identifier - cookie content - cookie expiration date. Use for session cookie. - id or content is null - id is empty - - - - Create a new cookie - - name identifying the cookie - cookie value - when the cookie expires. Setting will delete the cookie when the session is closed. - Path to where the cookie is valid - Domain that the cookie is valid for. - - - - Create a new cookie - - Name and value will be used - when the cookie expires. - - - - Gets the cookie HTML representation. - - cookie string - - - - Gets when the cookie expires. - - means that the cookie expires when the session do so. - - - - Gets path that the cookie is valid under. - - - - - The Cache-Control general-header field is used to specify directives that - MUST be obeyed by all caching mechanisms along the request/response - chain. . - - - - The directives specify behavior intended to prevent caches from adversely - interfering with the request or response. These directives typically - override the default caching algorithms. Cache directives are - unidirectional in that the presence of a directive in a request does not - imply that the same directive is to be given in the response. - Note that HTTP/1.0 caches might not implement Cache-Control and - might only implement Pragma: no-cache (see section 14.32 in RFC2616). - Cache directives MUST be passed through by a proxy or gateway - application, regardless of their significance to that application, since the - directives might be applicable to all recipients along the request/response - chain. It is not possible to specify a cache- directive for a specific cache - - - When a directive appears without any 1#field-name parameter, the - directive applies to the entire request or response. When such a - directive appears with a 1#field-name parameter, it applies only to - the named field or fields, and not to the rest of the request or - response. This mechanism supports extensibility; implementations of - future versions of the HTTP protocol might apply these directives to - header fields not defined in HTTP/1.1. - - - The cache-control directives can be broken down into these general - categories: - - - Restrictions on what are cacheable; these may only be imposed by - the origin server. - - Restrictions on what may be stored by a cache; these may be - imposed by either the origin server or the user agent. - - Modifications of the basic expiration mechanism; these may be - imposed by either the origin server or the user agent. - - Controls over cache revalidation and reload; these may only be - imposed by a user agent. - - Control over transformation of entities. - - Extensions to the caching system. - - - - - - - - Header name - - - - - Gets header name - - - - - Serves files in the web server. - - - - FileModule fileModule = new FileModule(); - fileModule.Resources.Add(new FileResources("/", "C:\\inetpub\\myweb")); - - - - - - Initializes a new instance of the class. - - baseUri or basePath is null. - - - - Mime types that this class can handle per default - - - Contains the following mime types: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Will send a file to client. - - HTTP context containing outbound stream. - Response containing headers. - File stream - - - - Process a request. - - Request information - What to do next. - Failed to find file extension - Forbidden file type. - - - - Gets a list with all allowed content types. - - All other mime types will result in . - - - - Gets provider used to add files to the file manager, - - - - - Collection of files. - - - - - Checks if a file exists. - - Name of the file (form item name) - - - - - Add a new file. - - File to add. - - - - Remove all files from disk. - - - - - Get a file - - Name in form - File if found; otherwise null. - - - - Gets number of files - - - - + + + + HttpServer + + + + + Used by to filter out unwanted connections. + + + + + Initializes a new instance of the class. + + The socket. + + + + Gets or sets if socket can be accepted. + + + + + Gets socket. + + + + + A request have been received. + + + + + + + Initializes a new instance of the class. + + context that received the request. + Received request. + Response to send. + + + + Gets context that received the request. + + + Do not forget to set to true if you are sending + back a response manually through . + + + + + Gets or sets if the request have been handled. + + + The library will not attempt to send the response object + back to the client if this property is set to true. + + + + + Gets request object. + + + + + Gets response object. + + + + + Cookies that should be set. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name and Content must be specified. + + + + Copy a request cookie + + + When the cookie should expire + + + + Remove all cookies + + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier. + + Cookie if found; otherwise null. + + + + An exception that can't be handled by the library have been thrown. + + + + + Initializes a new instance of the class. + + The exception. + + + + Gets caught exception. + + + + + Data decoded from a POST body. + + + + + Initializes a new instance of the class. + + + + + Gets or sets decoded files. + + + + + Gets or sets decoded parameters. + + + + + Stores sessions in files. + + + All session parameters must be serializable. + + + + + Stores sessions in your favorite store + + + + + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + Delete a session + + Id of session + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + HTTP methods. + + + + + Unknown method + + + + + Posting data + + + + + Get data + + + + + Update data + + + + + Remove data + + + + + Get only HTTP headers. + + + + + Options HTTP 1.1 header. + + + + + Http listener. + + + + + Http listener + + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + Gets the maximum content size. + + The content length limit. + + Used when responding to 100-continue. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Initializes a new instance of the class. + + The address. + The port. + + + + Initializes a new instance of the class. + + The address. + The port. + The HTTP factory. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Factory used to create different types in the framework. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Certificate to use + Created HTTP listener. + + + + Create a new context + + Accepted socket + A new context. + + + Throwing exception if in debug mode and not exception handler have been specified. + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets HTTP factory used to create types used by this HTTP library. + + + + + Gets or sets the maximum number of bytes that the request body can contain. + + The content length limit. + + + Used when responding to 100-continue. + + + 0 = turned off. + + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Contents of a cookie header. + + + + + Header in a message + + + Important! Each header should override ToString() + and return it's data correctly formatted as a HTTP header value. + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + Initializes a new instance of the class. + + The collection. + collection is null. + + + + Gets cookie collection + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + + Request couldn't be parsed successfully. + + + + + Exception thrown from HTTP server. + + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + Inner exception. + + + + Gets HTTP status code. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Something failed during parsing. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Used to parse header values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Collection of body decoders. + + + Body decoders are used to parse request body and convert it + into a and a . + + + + + Add another body decoder. + + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets number of decoders. + + + + + Custom network stream to mark sockets as reusable when disposing the stream. + + + + + Creates a new instance of the class for the specified . + + + The that the will use to send and receive data. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Initializes a new instance of the class for the specified with the specified ownership. + + + The that the will use to send and receive data. + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + the value of the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specify the type of access given to the over the provided . + + + The parameter is null. + + + The parameter is not connected. + -or- + the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specifies the type of access given to the over the provided . + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + + + + + Releases the unmanaged resources used by the and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Parses query string + + + + + Parse a query string + + string to parse + A collection + reader is null. + + + + Parse a query string + + string to parse + A collection + queryString is null. + + + + Convention over configuration server. + + + Used to make it easy to create and use a web server. + + All resources must exist in the "YourProject.Content" namespace (or a subdirectory called "Content" relative to yourapp.exe). + + + + + + Http server. + + + + + Initializes a new instance of the class. + + Factory used to create objects used in this library. + + + + Initializes a new instance of the class. + + + + + Add a decoder. + + decoder to add + + Adding zero decoders will make the server add the + default ones which is and . + + + + + Add a new router. + + Router to add + Server have been started. + + + + Add a file module + + Module to add + module is null. + Cannot add modules when server have been started. + + + + Add a HTTP listener. + + + Listener have been started. + + + + An error have occurred and we need to send a result pack to the client + + The context. + The exception. + + Invoke base class () to send the contents + of . + + + + + Called before anything else. + + The context. + + Looks after a in the request and will + use the if found. + + + + + All server modules are about to be invoked. + + The context. + + Called when routers have been invoked but no modules yet. + + + + + A request have arrived but not yet been processed yet. + + The context. + + Default implementation adds a Date header and Server header. + + + + + Go through all modules and check if any of them can handle the current request. + + + + + + + Process result (check if it should be sent back or not) + + + + true if request was processed properly.; otherwise false. + + + + Processes all routers. + + Request context. + Processing result. + + + + Requests authentication from the user. + + Host/domain name that the server hosts. + + Used when calculating hashes in Digest authentication. + + + + + + + Send a response. + + + + + + + + Start http server. + + Number of pending connections. + + + + Stops the server + + true if all modules should be removed. + + + + Gets the authentication provider. + + + A authentication provider is used to keep track of all authentication types + that can be used. + + + + + Gets or sets number of bytes that a body can be. + + + + Used to determine the answer to a 100-continue request. + + + 0 = turned off. + + + + + + Gets current server. + + + Only valid when a request have been received and is being processed. + + + + + Gets or sets the maximum size of request body (in bytes) + + + + + Gets or sets server name. + + + Used in the "Server" header when serving requests. + + + + + Invoked just before a response is sent back to the client. + + + + + Invoked *after* the web server has tried to handled the request. + + + The event can be used to handle the request after all routes and modules + have tried to process the request. + + + + + Invoked *before* the web server has tried to handled the request. + + + Event can be used to load a session from a cookie or to force + authentication or anything other you might need t do before a request + is handled. + + + + + An error page have been requested. + + + + + Initializes a new instance of the class. + + + + + Used to build headers. + + + + + Add a parser + + Header that the parser is for. + Parser implementation + + Will replace any existing parser for the specified header. + + + + + Add all default (built-in) parsers. + + + Will not replace previously added parsers. + + + + + Create a header parser + + implementation. + + + Uses attribute to find which headers + the parser is for. + + Will not replace previously added parsers. + + + + + Parse a header. + + Name of header + Header value + Header. + Value is not a well formatted header value. + + + + Request sent to a HTTP server. + + + + + + Base interface for request and response. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Gets or sets connection header. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets form parameters. + + + + + Gets or sets HTTP version. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets HTTP method. + + + + + Gets query string and form parameters + + + + + Gets query string. + + + + + Gets requested URI. + + + + + Load resources from disk. + + + + + Loads resources from a specific location (such as assembly, hard drive etc). + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Default forbidden characters. + + + + + relative to absolute path mappings. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + new FileResources("/files/user/", "C:\\intetpub\\files\users\\"); + + + + + + Add a new resource mapping. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + resources.Add("/files/", "C:\\intetpub\\files\\"); + + + absolutePath is not found. + + + + check if source contains any of the chars. + + string to check + Characters to fined + + + + + Go through all mappings and find requested Uri. + + Uri to get local path for. + Path if found; otherwise null. + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + Uri contains forbidden characters. + + Find(" + + + + + Gets or sets forbidden characters. + + + Used to revoke access to any system files. + + + + + Gets or sets absolute path on disk, including file name. + + + + + Gets or sets relative file path. + + + + + Gets or sets Uri path, excluding file name + + + + + Used to send a response back to the client. + + + + Writes a object into a stream. + + + Important! ResponseWriter do not throw any exceptions. Instead it just logs them and + let them die peacefully. This is since the response writer is used from + catch blocks here and there. + + + + + + Sends response using the specified context. + + The context. + The response. + + + + Converts and sends a string. + + + + Encoding used to transfer string + + + + Send a body to the client + + Context containing the stream to use. + Body to send + + + + Send all headers to the client + + Response containing call headers. + Content used to send headers. + + + + Decodes body stream. + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + Decodes forms that have multiple sections. + + + http://www.faqs.org/rfcs/rfc1867.html + + + + + form-data + + + + + multipart/form-data + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + stream is null. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + Provides sessions. + + Type of session object + + Will always use files for sessions (utilizing the binary formatter), but can + also cache them in memory. + + If caching is enabled, it will only write sessions to disk every 20 seconds if they have + been accessed the last minute (to not keep writing dead sessions to disk). + + + + + + Initializes a new instance of the class. + + Session type must use [Serializable] attribute. + + + + Create a new session. + + + + + + Load session + + Id of session. + Session if found; otherwise null. + sessionId is null. + + + + Load session when a new request comes in. + + + + + + + Save a session to disk. + + Session to write to disk. + + You are responsible for writing sessions to disk if you are not using caching. + + + + + Start the session system and hook + + + + + + Stop session handling + + + + + Gets or sets session cookie name + + + + + Gets or sets cache + + + + + Gets current session. + + + + + Gets or sets number of seconds before a session expired. + + + A session have expired if nothing have accessed it for X seconds. This + class modifies the write time each time it's accessed. + + + + + Determines if cookie should be set in the response. + + + + + Invoked when a session have been changed and should be written to disc. + + + + + First line in a response have been received + + + + + Gets or sets motivation to why the status code was used. + + + + + Gets or sets message status code + + + + + Gets or sets sip protocol version used. + + + + + A request have been parsed successfully by the server. + + + + + Initializes a new instance of the class. + + Received request. + + + + Gets received request. + + + + + Provider returning user to be authenticated. + + + + + Lookups the specified user + + User name. + Typically web server domain name. + User if found; otherwise null. + + User name can basically be anything. For instance name entered by user when using + basic or digest authentication, or SID when using Windows authentication. + + + + + Gets the principal to use. + + Successfully authenticated user. + + + Invoked when a user have successfully been authenticated. + + + + + + + User information used during authentication process. + + + + + Gets or sets user name used during authentication. + + + + + Gets or sets unencrypted password. + + + Password as clear text. You could use instead if your passwords + are encrypted in the database. + + + + + Gets or sets HA1 hash. + + + + Digest authentication requires clear text passwords to work. If you + do not have that, you can store a HA1 hash in your database (which is part of + the Digest authentication process). + + + A HA1 hash is simply a Md5 encoded string: "UserName:Realm:Password". The quotes should + not be included. Realm is the currently requested Host (as in Request.Headers["host"]). + + + Leave the string as null if you are not using HA1 hashes. + + + + + + Used to get or set properties on objects. + + + This class should be a bit faster than the standard reflection. + + + + + Get cached type. + + Type to get/set properties in + Type to use + + + + Used to load/store sessions in the server. + + + + + Initializes a new instance of the class. + + Web server that the provider is for.. + Store to use. + + + + Initializes a new instance of the class. + + The server. + + Uses a file store. + + + + + Loads a session for all requests that got the session cookie. + + The sender. + The instance containing the event data. + + + + Gets current session + + Session if set, otherwise null. + + + + Gets or sets the session life time in minutes. + + The session life time. + + + + A session have been loaded. Use to access it. + + + + + Secure version of the HTTP listener. + + + + + Initializes a new instance of the class. + + Address to accept new connections on. + Port to accept connections on. + Certificate securing the connection. + + + + Create a new context + + Accepted socket + A new context. + + Factory is assigned by the on each incoming request. + + + + + Gets if listener is secure. + + + + + + Gets or sets SSL protocol. + + + + + Gets or sets if client certificate should be used. + + + + + Arguments used when more body bytes have come. + + + + + Initializes a new instance of the class. + + buffer that contains the received bytes. + offset in buffer where to start processing. + number of bytes from that should be parsed. + buffer is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets buffer that contains the received bytes. + + + + + Gets or sets number of bytes from that should be parsed. + + + + + Gets or sets offset in buffer where to start processing. + + + + + HTTP Module + + + + + Process a request. + + Request information + What to do next. + + + + Something unexpected went wrong. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + File sent from remote end. + + + + + Gets or sets content type. + + + + + Gets or sets name in form. + + + + + Gets or sets name original file name + + + + + Gets or sets filename for locally stored file. + + + + + Parses Cookie header. + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Decodes URL encoded values. + + + + + + + Stream containing the content + Content type header + Stream encoding + Collection with all parameters. + Body format is invalid for the specified content type. + Failed to read all bytes from body stream. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + Base class for sessions. + + + Your class must be tagged with attribute to be able to use sessions. + + + + + The session have been changed and should be written to disk. + + + + + Session have been changed. + + + + + Gets or sets when session was accessed last + + + + + Gets current session. + + + + + Gets or sets session id. + + + + + Gets or sets when the session was last written to disk. + + + + + Parses and builds messages + + + The message factory takes care of building messages + from all end points. + + Since both message and packet protocols are used, the factory + hands out contexts to all end points. The context keeps a state + to be able to parse partial messages properly. + + + Each end point need to hand the context back to the message factory + when the client disconnects (or a message have been parsed). + + + + + + Initializes a new instance of the class. + + Factory used to create headers. + + + + Create a new message factory context. + + A new context. + + A context is used to parse messages from a specific endpoint. + + + + + Release a used factory context. + + + + + + A request have been received from one of the end points. + + + + + A response have been received from one of the end points. + + + + + Interface used to write to log files. + + + If you want to use the built in filtering mechanism, create a constructor + which takes one parameter, a . + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + cookie sent by the client/browser + + + + + + Constructor. + + cookie identifier + cookie content + id or content is null + id is empty + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets the cookie identifier. + + + + + Gets value. + + + Set to null to remove cookie. + + + + + Arguments for . + + + + + Initializes a new instance of the class. + + The context. + + + + Gets or sets thrown exception + + + + + Gets or sets if error page was provided. + + + + + Gets requested resource. + + + + + Gets response to send + + + + + Implements HTTP Digest authentication. It's more secure than Basic auth since password is + encrypted with a "key" from the server. + + + Keep in mind that the password is encrypted with MD5. Use a combination of SSL and digest auth to be secure. + + + + + Authenticates requests + + + + + Authenticate request + + Authorization header send by web client + Realm to authenticate in, typically a domain name. + HTTP Verb used in the request. + User if authentication was successful; otherwise null. + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A WWW-Authenticate header. + If realm is empty or null. + + + + Gets authenticator scheme + + + digest + + + + + Initializes a new instance of the class. + + Supplies users during authentication process. + + + + Used by test classes to be able to use hardcoded values + + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + + Authentication object that is stored for the request. A user class or something like that. + + if authenticationHeader is invalid + If any of the parameters is empty or null. + + + + Encrypts parameters into a Digest string + + Realm that the user want to log into. + User logging in + Users password. + HTTP method. + Uri/domain that generated the login prompt. + Quality of Protection. + "Number used ONCE" + Hexadecimal request counter. + "Client Number used ONCE" + Digest encrypted string + + + + + + Md5 hex encoded "userName:realm:password", without the quotes. + Md5 hex encoded "method:uri", without the quotes + Quality of Protection + "Number used ONCE" + Hexadecimal request counter. + Client number used once + + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A correct auth request. + If realm is empty or null. + + + + Gets the current nonce. + + + + + + Gets the Md5 hash bin hex2. + + To be hashed. + + + + + determines if the nonce is valid or has expired. + + nonce value (check wikipedia for info) + true if the nonce has not expired. + + + + Gets authentication scheme name + + + + + Gets authenticator scheme + + + + digest + + + + + Provides authentication in the web server. + + + To initiate authentication you just need to throw a Una + + + + + Add a authenticator. + + + + + + Authenticate request. + + + + + Requires that a AuthorizationHeader have been sent by the client. If not, + request one by sending a WWW-Authentication header (can be generated by the Challenge method). + + Authorization header was not found in the request. + Requested authentication scheme is not supported. + + + + Create a challenge header (WWW-authenticate) + + Response that the authentication header should be added to + Realm that the user should authenticate in + WWW-Authenticate header. + + + Scheme can currently be basic or digest. Basic is not very safe, but easier to use. + Digest is quite safe. + + + + Requested scheme is not supported. + + + + Creates a console logger. + + + + + Factory implementation used to create logs. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Initializes a new instance of the class. + + The filter. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + redirects from one URL to another. + + + + + Rules are used to perform operations before a request is being handled. + Rules can be used to create routing etc. + + + + + Process the incoming request. + + Request context information. + Processing result. + If any parameter is null. + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + true if request should be redirected, false if the request URI should be replaced. + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + Gets string to match request URI with. + + Is compared to request.Uri.AbsolutePath + + + + Gets whether the server should redirect the client instead of simply modifying the URI. + + + false means that the rule will replace + the current request URI with the new one from this class. + true means that a redirect response is sent to the client. + + + + + Gets where to redirect. + + + + + The Connection general-header field allows the sender to specify options + that are desired for that particular connection and MUST NOT be + communicated by proxies over further connections. + + + + HTTP/1.1 proxies MUST parse the Connection header field before a + message is forwarded and, for each connection-token in this field, + remove any header field(s) from the message with the same name as the + connection-token. Connection options are signaled by the presence of + a connection-token in the Connection header field, not by any + corresponding additional header field(s), since the additional header + field may not be sent if there are no parameters associated with that + connection option. + + Message headers listed in the Connection header MUST NOT include + end-to-end headers, such as Cache-Control. + + HTTP/1.1 defines the "close" connection option for the sender to + signal that the connection will be closed after completion of the + response. For example, + + Connection: close + + in either the request or the response header fields indicates that + the connection SHOULD NOT be considered `persistent' (section 8.1) + after the current request/response is complete. + + HTTP/1.1 applications that do not support persistent connections MUST + include the "close" connection option in every message. + + A system receiving an HTTP/1.0 (or lower-version) message that + includes a Connection header MUST, for each connection-token in this + field, remove and ignore any header field(s) from the message with + the same name as the connection-token. This protects against mistaken + forwarding of such header fields by pre-HTTP/1.1 proxies. See section + 19.6.2 in RFC2616. + + + + + + Header name + + + + + Default connection header for HTTP/1.0 + + + + + Default connection header for HTTP/1.1 + + + + + Initializes a new instance of the class. + + Connection type. + The parameters. + + + + Initializes a new instance of the class. + + The type. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets connection parameters. + + + + + Gets or sets connection type + + + + + Gets header name + + + + + Type of HTTP connection + + + + + Connection is closed after each request-response + + + + + Connection is kept alive for X seconds (unless another request have been made) + + + + + Requests message-body be sent with an encoding to be specified in the "Transfer-Encoding" header. + + + + + Helper for content types. + + + + + Flyweight design pattern implementation. + + Type of object. + + + + Initializes a new instance of the class. + + How large buffers to allocate. + + + + Get an object. + + Created object. + Will create one if queue is empty. + + + + Enqueues the specified buffer. + + Object to enqueue. + Buffer is is less than the minimum requirement. + + + + Used to create new objects. + + Type of objects to create. + Newly created object. + . + + + + A HTTP parser using delegates to which parsing methods. + + + + + Initializes a new instance of the class. + + + + + Parser method to copy all body bytes. + + + Needed since a TCP packet can contain multiple messages + after each other, or partial messages. + + + + Try to find a header name. + + + + + + Get header values. + + + Will also look for multi header values and automatically merge them to one line. + Content length is not a number. + + + + Toggle body bytes event. + + + + + + + + Raise the event, since we have successfully parsed a message and it's body. + + + + + First message line. + + Will always contain three elements. + Used to raise the or event + depending on the words in the array. + BadRequestException. + + + + Continue parsing a message + + Byte buffer containing bytes + Where to start the parsing + Number of bytes to parse + index where the parsing stopped. + Parsing failed. + + + + Parses the first line in a request/response. + + true if first line is well formatted; otherwise false. + Invalid request/response line. + + + + Reset parser to initial state. + + + + + Gets or sets current line number. + + + + + The request line has been parsed. + + + + + Response line has been parsed. + + + + + Parsed a header. + + + + + Received body bytes. + + + + + A message have been successfully parsed. + + + + + Used to be able to quickly swap parser method. + + + + + + Get or create components used in the web server framework + + + + + + + + Get or create a type. + + Type to create + Created type. + + Gets or creates types in the framework. + Check for more information on which + types the factory should contain. + + + + + Used to create all key types in the HTTP server. + + + Should have factory methods at least for the following types: + , , + , , + , , + , , + . + + Check the default implementations to see which constructor + parameters you will get. + + + HttpFactory.Add(typeof(IRequest), (type, args) => new MyRequest((string)args[0])); + + + + + + Initializes a new instance of the class. + + + + + Add a factory method for a type. + + Type to create + Method creating the type. + + + + Used to + + + + + + + Setup our singleton. + + + + + + We want to use a singleton, but we also want to be able + to let the developer to setup his own header factory. + Therefore we use this method to create our own factory only if the user + have not specified one. + + + + + Small method to create a message factory singleton and replace then default delegate method. + + + + + + + + Create a type. + + Type to create + Created type. + + + + Gets http factory for the current listener. + + + + + Delegate used to create a certain type + + Created type. + + Method must never fail. + + + + + Used to define which headers a parse is for. + + + + + Initializes a new instance of the class. + + Name of the header. + + + + Gets name of header that this parser is for. + + + + + Parses "Date" header. + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Authorization response + + + + A user agent that wishes to authenticate itself with a server-- + usually, but not necessarily, after receiving a 401 response--does + so by including an Authorization request-header field with the + request. The Authorization field value consists of credentials + containing the authentication information of the user agent for + the realm of the resource being requested. + + + Authorization = "Authorization" ":" credentials + + + HTTP access authentication is described in "HTTP Authentication: + Basic and Digest Access Authentication" [43]. If a request is + authenticated and a realm specified, the same credentials SHOULD + be valid for all other requests within this realm (assuming that + the authentication scheme itself does not require otherwise, such + as credentials that vary according to a challenge value or using + synchronized clocks). + When a shared cache (see section 13.7) receives a request + containing an Authorization field, it MUST NOT return the + corresponding response as a reply to any other request, unless one + of the following specific exceptions holds: + + + + If the response includes the "s-maxage" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But (if the specified maximum age has + passed) a proxy cache MUST first revalidate it with the origin + server, using the request-headers from the new request to allow + the origin server to authenticate the new request. (This is the + defined behavior for s-maxage.) If the response includes "s- + maxage=0", the proxy MUST always revalidate it before re-using + it. + + If the response includes the "must-revalidate" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But if the response is stale, all caches + MUST first revalidate it with the origin server, using the + request-headers from the new request to allow the origin server + to authenticate the new request. + + If the response includes the "public" cache-control directive, + it MAY be returned in reply to any subsequent request. + + + + + + + Name constant + + + + + Gets or sets authentication data. + + + + + Gets or sets authentication protocol. + + + + + Gets name of header. + + + + + User needs to authenticate. + + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + A response have been received. + + + + + Initializes a new instance of the class. + + The response. + + + + Gets or sets response. + + + + + Creates a single message for one of the end points. + + + The factory is + + + + + Initializes a new instance of the class. + + The MSG factory. + The factory. + The parser. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Received a header from parser + + + + + + + Will continue the parsing until nothing more can be parsed. + + buffer to parse + where to start in the buffer + number of bytes to process. + Position where parser stopped parsing. + Parsing failed. + + + + Reset parser. + + + Something failed, reset parser so it can start on a new request. + + + + + A request have been successfully parsed. + + + + + A response have been successfully parsed. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Used to notify about 100-continue header. + + + + + Initializes a new instance of the class. + + request that want to continue. + + + + Gets request that want to continue + + + + + Default log filter implementation. + + + + + Determines which classes can log + + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + + Add a name space filter. + + Name space to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Used to specify standard filter rules + + + Parser can only display errors. Transports only warnings. + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType("SipSharp.Messages.MessageFactory", LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + Type could not be identified. + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + No filters = everything logged. = no logs. Don't use a rule with '*' or '.*' + + + + User have specified a wild card filter. + + + Wild card filters are used to log a name space and + all it's children name spaces. + + + + + Result of processing. + + + + + Continue with the next handler + + + + + No more handlers can process the request. + + + The server will process the response object and + generate a HTTP response from it. + + + + + Response have been sent back by the handler. + + + This option should only be used if you are streaming + something or sending back a custom result. The server will + not process the response object or send anything back + to the client. + + + + + Used to store all headers that that aren't recognized. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Gets or sets value + + + + + Gets header name + + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Collection of parameters + + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Parameter in + + + + + Gets *last* value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + A parameter in . + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets last value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + Used when the request line have been successfully parsed. + + + + + Initializes a new instance of the class. + + The HTTP method. + The URI path. + The HTTP version. + + + + Initializes a new instance of the class. + + + + + Gets or sets HTTP method. + + + Should be one of the methods declared in . + + + + + Gets or sets requested URI path. + + + + + Gets or sets the version of the SIP protocol that the client want to use. + + + + + Content-type + + + + + Header name. + + + + + Initializes a new instance of the class. + + Type of the content. + Value parameters. + + + + Initializes a new instance of the class. + + Type of the content. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets all parameters. + + + + + Gets content type. + + + + + Gets header name + + + + + Requested resource may not be accessed. + + + Normally thrown after an authentication attempt have failed too many times. + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Stream-based multipart handling. + + In this incarnation deals with an HttpInputStream as we are now using + IntPtr-based streams instead of byte []. In the future, we will also + send uploads above a certain threshold into the disk (to implement + limit-less HttpInputFiles). + + + Taken from HttpRequest in mono (http://www.mono-project.com) + + + + + Client X.509 certificate, X.509 chain, and any SSL policy errors encountered + during the SSL stream creation + + + + + Initializes a new instance of the class. + + The certificate. + Client security certificate chain. + Any SSL policy errors encountered during the SSL stream creation. + + + + Client security certificate + + + + + Client security certificate chain + + + + + Any SSL policy errors encountered during the SSL stream creation + + + + + Credits and description: http://theinstructionlimit.com/?p=76 + + + Converted to .Net 2.0 + + + + + Session in the system + + + + + Gets or sets session id. + + + + + Factory creating null logger. + + + + + Initializes a new instance of the class. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Logger instance. + + + + + Provides resources. + + + + + Used to access resources. + + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Start manager. + + + + + Gets number of resource providers + + + + + Get all view names from a folder. + + Path to find views in. + A collection of view names (without path). + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Start manager. + + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Gets number of resource providers + + + + + Loads resources that are embedded in assemblies. + + + No locks used internally since all mappings are loaded during start up. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space that the resources exist in + + + + Add a specific resource. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under (all name spaces below the specified one are considered as folders) + Name space and name of resource. + + + Add("/", Assembly.GetExecutingAssembly(), "MyApplication.Files", "Myapplication.Files.Images.MyImage.png"); + + + + + + Add resources. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name of resource, including name space. + true if file was found (and has not previously been added); otherwise false. + + + + + + Add resources in a specific path (will not work with sub folders) + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under which all name spaces exists in, + true if any files was found; otherwise false. + + + Adds all views in the specified folder. Sub folders are not supported since it's hard to determine + with parts are the path and witch parts are the filename. Use to get support + for sub folders. + + + + + Add("/user/", typeof(MyController).Assembly, "YourProject.Users.Views"); + + + + + + Add resources in a folder and it's sub folder + + + + + + This method is not going to map files but keep the mapping and + try to look up views every time they are requested. This is the method + to use to add a resource folder that has sub folders. + + + + + + Tries to load file by using previously added paths. + + Uri path including file name + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Load a resource. + + Uri of resource. + Resource if found and loaded; otherwise null. + + + + Find all views in a folder/path. + + Uri path + Collection to add all view names to. + + + + Loads all files in a resource directory + + + + + + Gets or sets assembly that the resource exists in. + + + + + Gets or sets resource name. + + + + + Gets or sets full name space path to resource. + + + + + Gets or sets if this file is for a certain content type. + + + + + Gets or sets full "virtual" Uri path, excluding file name. + + + + + Gets or sets assembly + + + + + Gets or sets name space root. + + + + + Gets or sets uri path. + + + + + A list of request cookies. + + + + + Let's copy all the cookies. + + value from cookie header. + + + + Initializes a new instance of the class. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name must be specified. + + + + Remove all cookies. + + + + + Remove a cookie from the collection. + + Name of cookie. + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier (null if not existing). + + + + + Collection of headers. + + + + + Collection of headers. + + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Initializes a new instance of the class. + + Factory used to created headers. + + + + Adds a header + + + Will replace any existing header with the same name. + + header to add + header is null. + Header name cannot be null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + Header value is not correctly formatted. + name or value is null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + name or value is null. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Header for "Date" and "If-Modified-Since" + + + + The field value is an HTTP-date, as described in section 3.3.1 in RFC2616; + it MUST be sent in RFC 1123 [8]-date format. An example is + + Date: Tue, 15 Nov 1994 08:12:31 GMT + + Origin servers MUST include a Date header field in all + responses, except in these cases: + + If the response status code is 100 (Continue) or 101 (Switching + Protocols), the response MAY include a Date header field, at the server's + option. + If the response status code conveys a server error, e.g. 500 + (Internal Server Error) or 503 (Service Unavailable), and it is inconvenient + or impossible to generate a valid Date. + If the server does not have a clock that can provide a + reasonable approximation of the current time, its responses MUST NOT include + a Date header field. In this case, the rules in section 14.18.1 in RFC2616 + MUST be followed. + + + A received message that does not have a Date header field MUST + be assigned one by the recipient if the message will be cached by that + recipient or gatewayed via a protocol which requires a Date. An HTTP + implementation without a clock MUST NOT cache responses without revalidating + them on every use. An HTTP cache, especially a shared cache, SHOULD use a + mechanism, such as NTP [28], to synchronize its clock with a reliable + external standard. + Clients SHOULD only send a Date header field in messages that + include an entity-body, as in the case of the PUT and POST requests, and + even then it is optional. A client without a clock MUST NOT send a Date + header field in a request. + The HTTP-date sent in a Date header SHOULD NOT represent a date + and time subsequent to the generation of the message. It SHOULD represent + the best available approximation of the date and time of message generation, + unless the implementation has no means of generating a reasonably accurate + date and time. In theory, the date ought to represent the moment just before + the entity is generated. In practice, the date can be generated at any time + during the message origination without affecting its semantic value. + + + + + + Header name + + + + + Initializes a new instance of the class. + + Header name. + Name must not be empty. + + + + Initializes a new instance of the class. + + Header name. + Universal time. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets or sets date time. + + Should be in UTC. + + + + Gets header name + + + + + Type cached for fast property value modifications. + + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Used to cache property information + + + + + Gets the property. + + The name. + + Failed to find property. + + + InvalidCastException. + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Gets or sets member info + + + + + Gets or sets member type + + + + + Base interface to read string tokens from different sources. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + + + + Assign a new buffer + + Buffer to process + + + + Consume current character. + + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + true if found; otherwise false. + + + + Read a character. + + Character if not EOF; otherwise null. + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + + Will not consume the delimiter. + + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + + Will not consume the delimiter. + + + + + Will read until specified delimiter is found. + + Character to stop at. + A string if the delimiter was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until one of the delimiters are found. + + characters to stop at + A string if one of the delimiters was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Gets current character + + if end of buffer. + + + + Gets if end of buffer have been reached + + + + + Gets if more bytes can be processed. + + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + Gets or sets line number. + + + + + Gets next character + + if end of buffer. + + + + Gets number of bytes left. + + + + + Factory is used to create new logs in the system. + + + + + Assigns log factory being used. + + The log factory. + A factory have already been assigned. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + + + Component that should be registered in the container. + + + Register using all interfaces that is specified in this assembly. + + + + + Used to authenticate users + + + Authentication is requested by throwing + + + + + Request implementation. + + + + + Initializes a new instance of the class. + + The method. + The path. + The version. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets request URI. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets query string and form parameters + + + + + Gets form parameters. + + + + + Gets query string. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets connection header. + + + + + Gets or sets HTTP version. + + + + + Gets or sets HTTP method. + + + + + Gets requested URI. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Event arguments used when a new header have been parsed. + + + + + Initializes a new instance of the class. + + Name of header. + Header value. + Name cannot be empty + value is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets header name. + + + + + Gets or sets header value. + + + + + Collection of parameters. + + + or is not used since each parameter can + have multiple values. + + + + + Initializes a new instance of the class. + + Collections to merge. + + Later collections will overwrite parameters from earlier collections. + + + + + Initializes a new instance of the class. + + + + + Get a list of string arrays. + + + + + + Get parameters + + Sub array (text array) + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Parses numerical values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Request couldn't be parsed successfully. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Implements basic authentication scheme. + + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + Not used by basic authentication + A WWW-Authenticate header. + Argument is null. + + + + An authentication response have been received from the web browser. + Check if it's correct + + Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + Authentication object that is stored for the request. A user class or something like that. + if authenticationHeader is invalid + If any of the paramters is empty or null. + + + + Gets authenticator scheme + + + + digest + + + + + Reads strings from a byte array. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Encoding to use when converting byte array to strings. + + + + Initializes a new instance of the class. + + Buffer to read from. + Encoding to use when converting byte array to strings. + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + Buffer needs to be a byte array + + + + Assign a new buffer + + Buffer to process + Buffer needs to be a byte array + + + + Consume current character. + + + + + Get a text line. + + + Will merge multi line headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Response to a request. + + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Gets connection type. + + + + + Gets cookies. + + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Status code that is sent to the client. + + Default is + + + + Gets or sets content type + + + + + Request context + + + Contains information about a HTTP request and where it came from. + + + + + Gets or sets http context. + + + + + Gets or sets http request. + + + + + Gets or sets http response. + + + + + Contains numerical value. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets value + + + + + Gets header name + + + + + Form parameters where form string arrays have been converted to real arrays. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Initializes a new instance of the class. + + Parse parameters from the this collection. + + + + Get a parameter. + + + + + + + Add a parameter + + Name of parameter, can contain a string array. + Value + + + ArrayParameterCollection array = new ArrayParameterCollection(); + array.Add("user[FirstName]", "Jonas"); + array.Add("user[FirstName]", "Arne"); + string firstName = array["user"]["FirstName"].Value; // "Arne" is returned + foreach (string value in array["user"]["FirstName"]) + Console.WriteLine(value); // each name is displayed. + + + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Gets first value of an item. + + + String if found; otherwise null. + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Assign properties from HTTP parameters. + + + + + Used to filter out properties. + + Filter handler. + Handler have already been set. + + + + Assign properties in the specified object. + + Object to fill. + Contains all parameters that should be assigned to the properties. + Properties was not found or value could not be converted. + Any parameter is null. + + + + Used to be able to filter properties + + Model having it's properties assigned + Property about to be assigned + Value to assign + true if value can be set; otherwise false. + + + + Failed to assign properties. + + + + + Initializes a new instance of the class. + + The property errors. + + + + Gets all errors during assignment. + + + Dictionary key is property name. + + + + + Used to read from a string object. + + + + + Initializes a new instance of the class. + + Buffer to process. + + + + Initializes a new instance of the class. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + MUST be of type . + buffer needs to be of type string + + + + Assign a new buffer + + Buffer to process + MUST be of type . + buffer needs to be of type string + + + + Consume current character. + + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs (or end, or end of line). + + + A string if a white space was found; otherwise null. + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Default log writer, writes everything to void (nowhere). + + + + + + The logging instance. + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Priority for log entries + + + + + + Very detailed logs to be able to follow the flow of the program. + + + + + Logs to help debug errors in the application + + + + + Information to be able to keep track of state changes etc. + + + + + Something did not go as we expected, but it's no problem. + + + + + Something that should not fail failed, but we can still keep + on going. + + + + + Something failed, and we cannot handle it properly. + + + + + This class writes to the console. + + + It colors the output depending on the log level + and includes a 3-level stack trace (in debug mode) + + + + + + Initializes a new instance of the class. + + Type being logged. + Log filter. + + + + Get color for the specified log level + + Level for the log entry + A for the level + + + + Write an entry + + Importance of the log message + The message. + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Gets or sets type that the logger is for + + + + + A HTTP context + + + + + + + + Context that received a HTTP request. + + + + + Disconnect context. + + + + + Gets if current context is using a secure connection. + + + + + Gets logger. + + + + + Gets remote end point + + + + + Gets stream used to send/receive data to/from remote end point. + + + + The stream can be any type of stream, do not assume that it's a network + stream. For instance, it can be a or a ZipStream. + + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + Initializes a new instance of the class. + + Socket received from HTTP listener. + Context used to parse incoming messages. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Disconnect context. + + + + + Close and release socket. + + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Interpret incoming data. + + + + + + A request was received from the parser. + + + + + + + Parse all complete requests in buffer. + + + offset in buffer where parsing stopped. + Parsing failed. + + + + Start content. + + A socket operation failed. + Reading from stream failed. + + + + Gets currently executing HTTP context. + + + + + Gets or sets description + + + + + gets factory used to build request objects + + + + + Gets socket + + + + + Gets remove end point + + + + + Gets network stream. + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + Gets logger. + + + + + Gets if current context is using a secure connection. + + + + + Triggered for all requests in the server (after the response have been sent) + + + + + Triggered for current request (after the response have been sent) + + + + + A new request have been received. + + + + + A new request have been received (invoked for ALL requests) + + + + + Client have been disconnected. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Initializes a new instance of the class. + + SSL protocol to use. + The socket. + The context. + Server certificate to use. + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Gets or sets client certificate. + + + + + Gets used protocol. + + + + + Gets or sets if client certificate should be used instead of server certificate. + + + + + Resource information. + + + Used by content providers to be able to get information + on resources (views, files etc). + + + + + Gets or sets date when resource was modified. + + + if not used. + + + Should always be universal time. + + + + + Gets or sets resource stream. + + + + + Contains parameters for HTTP headers. + + + + + Add a parameter + + name + value + + Existing parameter with the same name will be replaced. + + + + + Parse parameters. + + Parser containing buffer to parse. + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Parse parameters. + + Parser containing buffer to parse. + Parameter delimiter + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets or sets a value + + parameter name + value if found; otherwise null. + + + + Create a HTTP response object. + + + + + Initializes a new instance of the class. + + HTTP Version. + HTTP status code. + Why the status code was selected. + Version must start with 'HTTP/' + + + + Initializes a new instance of the class. + + Context that the response will be sent through. + Request that the response is for. + Version must start with 'HTTP/' + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets connection type. + + + + + Status code that is sent to the client. + + Default is + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets cookies. + + + + + Gets body stream. + + + + + Gets headers. + + + + + A request have been received. + + + + + Initializes a new instance of the class. + + The request. + End point that the request was received from. + + + + End point that the message was received from. + + + + + Received request. + + + + + Class to make dynamic binding of redirects. Instead of having to specify a number of similar redirect rules + a regular expression can be used to identify redirect URLs and their targets. + + + [a-z0-9]+)", "/users/${target}/?find=true", RegexOptions.IgnoreCase) + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + + [a-zA-Z0-9]+)", "/user/${first}")); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to use, can be null + + [a-zA-Z0-9]+)", "/user/{first}", RegexOptions.IgnoreCase)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to apply + true if request should be redirected, false if the request URI should be replaced. + + [a-zA-Z0-9]+)", "/user/${first}", RegexOptions.None)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + Argument is null. + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + cookie being sent back to the browser. + + + + + + Constructor. + + cookie identifier + cookie content + cookie expiration date. Use for session cookie. + id or content is null + id is empty + + + + Create a new cookie + + name identifying the cookie + cookie value + when the cookie expires. Setting will delete the cookie when the session is closed. + Path to where the cookie is valid + Domain that the cookie is valid for. + + + + Create a new cookie + + Name and value will be used + when the cookie expires. + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets when the cookie expires. + + means that the cookie expires when the session do so. + + + + Gets path that the cookie is valid under. + + + + + The Cache-Control general-header field is used to specify directives that + MUST be obeyed by all caching mechanisms along the request/response + chain. . + + + + The directives specify behavior intended to prevent caches from adversely + interfering with the request or response. These directives typically + override the default caching algorithms. Cache directives are + unidirectional in that the presence of a directive in a request does not + imply that the same directive is to be given in the response. + Note that HTTP/1.0 caches might not implement Cache-Control and + might only implement Pragma: no-cache (see section 14.32 in RFC2616). + Cache directives MUST be passed through by a proxy or gateway + application, regardless of their significance to that application, since the + directives might be applicable to all recipients along the request/response + chain. It is not possible to specify a cache- directive for a specific cache + + + When a directive appears without any 1#field-name parameter, the + directive applies to the entire request or response. When such a + directive appears with a 1#field-name parameter, it applies only to + the named field or fields, and not to the rest of the request or + response. This mechanism supports extensibility; implementations of + future versions of the HTTP protocol might apply these directives to + header fields not defined in HTTP/1.1. + + + The cache-control directives can be broken down into these general + categories: + + + Restrictions on what are cacheable; these may only be imposed by + the origin server. + + Restrictions on what may be stored by a cache; these may be + imposed by either the origin server or the user agent. + + Modifications of the basic expiration mechanism; these may be + imposed by either the origin server or the user agent. + + Controls over cache revalidation and reload; these may only be + imposed by a user agent. + + Control over transformation of entities. + + Extensions to the caching system. + + + + + + + + Header name + + + + + Gets header name + + + + + Serves files in the web server. + + + + FileModule fileModule = new FileModule(); + fileModule.Resources.Add(new FileResources("/", "C:\\inetpub\\myweb")); + + + + + + Initializes a new instance of the class. + + baseUri or basePath is null. + + + + Mime types that this class can handle per default + + + Contains the following mime types: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Will send a file to client. + + HTTP context containing outbound stream. + Response containing headers. + File stream + + + + Process a request. + + Request information + What to do next. + Failed to find file extension + Forbidden file type. + + + + Gets a list with all allowed content types. + + All other mime types will result in . + + + + Gets provider used to add files to the file manager, + + + + + Collection of files. + + + + + Checks if a file exists. + + Name of the file (form item name) + + + + + Add a new file. + + File to add. + + + + Remove all files from disk. + + + + + Get a file + + Name in form + File if found; otherwise null. + + + + Gets number of files + + + + diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs index 4bce32cc0..b871c6c1a 100644 --- a/TShockAPI/BackupManager.cs +++ b/TShockAPI/BackupManager.cs @@ -1,96 +1,96 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.IO; -using System.Threading; -using Terraria; - -namespace TShockAPI -{ - public class BackupManager - { - public string BackupPath { get; set; } - public int Interval { get; set; } - public int KeepFor { get; set; } - - private DateTime lastbackup = DateTime.UtcNow; - - public BackupManager(string path) - { - BackupPath = path; - } - - public bool IsBackupTime - { - get { return (Interval > 0) && ((DateTime.UtcNow - lastbackup).TotalMinutes >= Interval); } - } - - public void Backup() - { - lastbackup = DateTime.UtcNow; - ThreadPool.QueueUserWorkItem(DoBackup); - ThreadPool.QueueUserWorkItem(DeleteOld); - } - - private void DoBackup(object o) - { - try - { - string worldname = Main.worldPathName; - string name = Path.GetFileName(worldname); - - Main.worldPathName = Path.Combine(BackupPath, string.Format("{0}.{1:dd.MM.yy-HH.mm.ss}.bak", name, DateTime.UtcNow)); - - string worldpath = Path.GetDirectoryName(Main.worldPathName); - if (worldpath != null && !Directory.Exists(worldpath)) - Directory.CreateDirectory(worldpath); - - TShock.Utils.Broadcast("Server map saving, potential lag spike"); - Console.WriteLine("Backing up world..."); - - SaveManager.Instance.SaveWorld(); - Console.WriteLine("World backed up"); - Console.ForegroundColor = ConsoleColor.Gray; - Log.Info(string.Format("World backed up ({0})", Main.worldPathName)); - - Main.worldPathName = worldname; - } - catch (Exception ex) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Backup failed"); - Console.ForegroundColor = ConsoleColor.Gray; - Log.Error("Backup failed"); - Log.Error(ex.ToString()); - } - } - - private void DeleteOld(object o) - { - if (KeepFor <= 0) - return; - foreach (var fi in new DirectoryInfo(BackupPath).GetFiles("*.bak")) - { - if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalMinutes > KeepFor) - { - fi.Delete(); - } - } - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.IO; +using System.Threading; +using Terraria; + +namespace TShockAPI +{ + public class BackupManager + { + public string BackupPath { get; set; } + public int Interval { get; set; } + public int KeepFor { get; set; } + + private DateTime lastbackup = DateTime.UtcNow; + + public BackupManager(string path) + { + BackupPath = path; + } + + public bool IsBackupTime + { + get { return (Interval > 0) && ((DateTime.UtcNow - lastbackup).TotalMinutes >= Interval); } + } + + public void Backup() + { + lastbackup = DateTime.UtcNow; + ThreadPool.QueueUserWorkItem(DoBackup); + ThreadPool.QueueUserWorkItem(DeleteOld); + } + + private void DoBackup(object o) + { + try + { + string worldname = Main.worldPathName; + string name = Path.GetFileName(worldname); + + Main.worldPathName = Path.Combine(BackupPath, string.Format("{0}.{1:dd.MM.yy-HH.mm.ss}.bak", name, DateTime.UtcNow)); + + string worldpath = Path.GetDirectoryName(Main.worldPathName); + if (worldpath != null && !Directory.Exists(worldpath)) + Directory.CreateDirectory(worldpath); + + TShock.Utils.Broadcast("Server map saving, potential lag spike"); + Console.WriteLine("Backing up world..."); + + SaveManager.Instance.SaveWorld(); + Console.WriteLine("World backed up"); + Console.ForegroundColor = ConsoleColor.Gray; + Log.Info(string.Format("World backed up ({0})", Main.worldPathName)); + + Main.worldPathName = worldname; + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Backup failed"); + Console.ForegroundColor = ConsoleColor.Gray; + Log.Error("Backup failed"); + Log.Error(ex.ToString()); + } + } + + private void DeleteOld(object o) + { + if (KeepFor <= 0) + return; + foreach (var fi in new DirectoryInfo(BackupPath).GetFiles("*.bak")) + { + if ((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalMinutes > KeepFor) + { + fi.Delete(); + } + } + } + } } \ No newline at end of file diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 29923559d..b0c6e68e6 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team @@ -583,10 +583,10 @@ private static void ManageUsers(CommandArgs args) // User deletion requires a username else if (subcmd == "del" && args.Parameters.Count == 2) { - var user = new User(); - if (args.Parameters[1].Split('.').Count() ==4) - - // changed to support dot character in usernames + var user = new User(); + if (args.Parameters[1].Split('.').Count() ==4) + + // changed to support dot character in usernames // if (args.Parameters[1].Contains(".")) user.Address = args.Parameters[1]; else @@ -632,7 +632,7 @@ private static void ManageUsers(CommandArgs args) // Group changing requires a username or IP address, and a new group to set else if (subcmd == "group") { - var user = new User(); + var user = new User(); if (args.Parameters[1].Split('.').Count()==4) //changed to support dot character in usernames @@ -1116,34 +1116,34 @@ private static void Ore(CommandArgs args) else if (args.Parameters[0] == "gold") { num = 5; - } - else if (args.Parameters[0] == "demonite") - { - num = 7; } - else if (args.Parameters[0] == "sapphire") - { - num = 8; - } - else if (args.Parameters[0] == "ruby") - { - num = 9; - } - else if (args.Parameters[0] == "emerald") - { - num = 10; - } - else if (args.Parameters[0] == "topaz") - { - num = 11; - } - else if (args.Parameters[0] == "amethyst") - { - num = 12; - } - else if (args.Parameters[0] == "diamond") - { - num = 13; + else if (args.Parameters[0] == "demonite") + { + num = 7; + } + else if (args.Parameters[0] == "sapphire") + { + num = 8; + } + else if (args.Parameters[0] == "ruby") + { + num = 9; + } + else if (args.Parameters[0] == "emerald") + { + num = 10; + } + else if (args.Parameters[0] == "topaz") + { + num = 11; + } + else if (args.Parameters[0] == "amethyst") + { + num = 12; + } + else if (args.Parameters[0] == "diamond") + { + num = 13; } else { @@ -1179,40 +1179,40 @@ private static void Ore(CommandArgs args) num = 9; num3 *= 1.1f; } - else if (num == 7) - { - num = 22; - num3 *= 1; - } - else if (num == 8) - { - num = 63; - num3 *= .80f; - } - else if (num == 9) - { - num = 64; - num3 *=1; - } - else if (num == 10) - { - num = 65; - num3 *= 1; - } - else if (num == 11) - { - num = 66; - num3 *= 1; - } - else if (num == 12) - { - num = 67; - num3 *= 1; - } - else if (num == 13) - { - num = 68; - num3 *= 1; + else if (num == 7) + { + num = 22; + num3 *= 1; + } + else if (num == 8) + { + num = 63; + num3 *= .80f; + } + else if (num == 9) + { + num = 64; + num3 *=1; + } + else if (num == 10) + { + num = 65; + num3 *= 1; + } + else if (num == 11) + { + num = 66; + num3 *= 1; + } + else if (num == 12) + { + num = 67; + num3 *= 1; + } + else if (num == 13) + { + num = 68; + num3 *= 1; } else { @@ -1598,38 +1598,38 @@ private static void RemoveSpecial(CommandArgs args) for (int x = 0; x < Main.maxTilesX; x++) { for (int y = 0; y < Main.maxTilesY; y++) - { - switch (Main.tile[x, y].type) - { - case 117: - case 25: - Main.tile[x, y].type = 1; - break; - case 109: - case 23: - Main.tile[x, y].type = 2; - break; - case 32: - case 113: - case 110: - Main.tile[x, y].type = 0; - Main.tile[x, y].active = false; - break; - case 24: - Main.tile[x, y].type = 3; - break; - case 112: - case 116: - Main.tile[x, y].type = 53; - break; - case 118: - Main.tile[x, y].type = 38; - break; - case 115: - Main.tile[x, y].type = 52; - break; - default: - continue; + { + switch (Main.tile[x, y].type) + { + case 117: + case 25: + Main.tile[x, y].type = 1; + break; + case 109: + case 23: + Main.tile[x, y].type = 2; + break; + case 32: + case 113: + case 110: + Main.tile[x, y].type = 0; + Main.tile[x, y].active = false; + break; + case 24: + Main.tile[x, y].type = 3; + break; + case 112: + case 116: + Main.tile[x, y].type = 53; + break; + case 118: + Main.tile[x, y].type = 38; + break; + case 115: + Main.tile[x, y].type = 52; + break; + default: + continue; } } } @@ -2262,7 +2262,7 @@ private static void SetSpawn(CommandArgs args) private static void Reload(CommandArgs args) { - FileTools.SetupConfig(); + FileTools.SetupConfig(); TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); TShock.Groups.LoadPermisions(); TShock.Regions.ReloadAllRegions(); diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index 4bb88a627..d03ff4f74 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -1,287 +1,287 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Text; -using Newtonsoft.Json; - -namespace TShockAPI -{ - public class ConfigFile - { - [Description( - "The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))" - )] public int InvasionMultiplier = 1; - - [Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")] public int - DefaultMaximumSpawns = 5; - - [Description("The delay between waves. Shorter values lead to less mobs.")] public int DefaultSpawnRate = 600; - [Description("The port the server runs on.")] public int ServerPort = 7777; - [Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")] public bool EnableWhitelist; - - [Description( - "Enable the ability for invaison size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn que for the map." - )] public bool InfiniteInvasion; - - [Description("Set the server pvp mode. Vaild types are, \"normal\", \"always\", \"disabled\"")] public string PvPMode - = "normal"; - - [Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")] public bool - SpawnProtection = true; - - [Description("Radius from spawn tile for SpawnProtection.")] public int SpawnProtectionRadius = 10; - - [Description( - "Max slots for the server. If you want people to be kicked with \"Server is full\" set this to how many players you want max and then set Terraria max players to 2 higher." - )] public int MaxSlots = 8; - - [Description("Global protection agent for any block distance based anti-grief check.")] public bool RangeChecks = true; - [Description("Disables any building; placing of blocks")] public bool DisableBuild; - - [Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")] public float[] - SuperAdminChatRGB = {255, 0, 0}; - - [Description("Super admin group chat prefix")] public string SuperAdminChatPrefix = "(Admin) "; - [Description("Super admin group chat suffix")] public string SuperAdminChatSuffix = ""; - - [Description( - "Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")] public int BackupInterval; - - [Description("How long backups are kept in minutes. 2880 = 2 days.")] public int BackupKeepFor = 60; - - [Description( - "Remembers where a player left off. It works by remembering the IP, NOT the character. \neg. When you try to disconnect, and reconnect to be automatically placed at spawn, you'll be at your last location. Note: Won't save after server restarts." - )] public bool RememberLeavePos; - - [Description("Hardcore players ONLY. This means softcore players cannot join.")] public bool HardcoreOnly; - [Description("Mediumcore players ONLY. This means softcore players cannot join.")] public bool MediumcoreOnly; - [Description("Kicks a Hardcore player on death.")] public bool KickOnMediumcoreDeath; - [Description("Bans a Hardcore player on death.")] public bool BanOnMediumcoreDeath; - - [Description("Enable/Disable Terrarias built in auto save")] public bool AutoSave = true; - - [Description("Number of failed login attempts before kicking the player.")] public int MaximumLoginAttempts = 3; - - [Description("Not implemented")] public string RconPassword = ""; - [Description("Not implemented")] public int RconPort = 7777; - - [Description("Used when replying to a rest /status request.")] public string ServerName = ""; - [Description("Not implemented")] public string MasterServer = "127.0.0.1"; - - [Description("Valid types are \"sqlite\" and \"mysql\"")] public string StorageType = "sqlite"; - - [Description("The MySQL Hostname and port to direct connections to")] public string MySqlHost = "localhost:3306"; - [Description("Database name to connect to")] public string MySqlDbName = ""; - [Description("Database username to connect with")] public string MySqlUsername = ""; - [Description("Database password to connect with")] public string MySqlPassword = ""; - - [Description("Bans a Mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban"; - [Description("Kicks a Mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick"; - - [Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")] public bool - EnableDNSHostResolution; - - [Description("Enables kicking of banned users by matching their IP Address")] public bool EnableIPBans = true; - - [Description("Enables kicking of banned users by matching their Character Name")] public bool EnableBanOnUsernames; - - [Description("Selects the default group name to place new registrants under")] public string - DefaultRegistrationGroupName = "default"; - - [Description("Selects the default group name to place non registered users under")] public string - DefaultGuestGroupName = "guest"; - - [Description("Force-Disable printing logs to players with the log permission")] public bool DisableSpewLogs = true; - - [Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms")] public string HashAlgorithm = "sha512"; - - [Description("Buffers up the packets and sends them out at the end of each frame")] public bool BufferPackets = true; - - [Description("String that is used when kicking people when the server is full.")] public string ServerFullReason = - "Server is full"; - - [Description("String that is used when kicking people when the server is full with no reserved slots.")] public string - ServerFullNoReservedReason = "Server is full. No reserved slots open."; - - [Description("This will save the world if Terraria crashes from an unhandled exception.")] public bool - SaveWorldOnCrash = true; - - [Description("This will announce a player's location on join")] public bool EnableGeoIP; - - [Description("This will turn on a token requirement for the /status API endpoint.")] public bool - EnableTokenEndpointAuthentication; - - [Description("This is used when the API endpoint /status is queried.")] public string ServerNickname = "TShock Server"; - - [Description("Enable/Disable the rest api.")] public bool RestApiEnabled; - - [Description("This is the port which the rest api will listen on.")] public int RestApiPort = 7878; - - [Description("Disable tombstones for all players.")] public bool DisableTombstones = true; - - [Description("Displays a player's IP on join to everyone who has the log permission")] public bool DisplayIPToAdmins; - - [Description( - "Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain asthetic tiles.")] public - bool EnableInsecureTileFixes = true; - - [Description("Kicks users using a proxy as identified with the GeoIP database")] public bool KickProxyUsers = true; - - [Description("Disables hardmode, can't never be activated. Overrides /starthardmode")] public bool DisableHardmode; - - [Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")] public bool DisableDungeonGuardian; - - [Description("Enable Server Side Inventory checks, EXPERIMENTAL")] public bool ServerSideInventory; - - [Description("How often SSI should save, in minutes")] public int ServerSideInventorySave = 15; - - [Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON")] public int LogonDiscardThreshold=250; - - [Description("Disables reporting of playercount to the stat system.")] public bool DisablePlayerCountReporting; - - [Description("Disables clown bomb projectiles from spawning")] public bool DisableClownBombs; - - [Description("Disables snow ball projectiles from spawning")] public bool DisableSnowBalls; - - [Description( - "Change ingame chat format, {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message" - )] public string ChatFormat = "{1}{2}{3}: {4}"; - - [Description("Force the world time to be normal, day, or night")] public string ForceTime = "normal"; - - [Description("Disable/Revert a player if they exceed this number of tile kills within 1 second.")] public int - TileKillThreshold = 60; - - [Description("Disable/Revert a player if they exceed this number of tile places within 1 second.")] public int - TilePlaceThreshold = 20; - - [Description("Disable a player if they exceed this number of liquid sets within 1 second.")] public int - TileLiquidThreshold = 15; - - [Description("Disable a player if they exceed this number of projectile new within 1 second.")] public int - ProjectileThreshold = 50; - - [Description("Ignore shrapnel from crystal bullets for Projectile Threshold.")] public bool - ProjIgnoreShrapnel = true; - - [Description("Require all players to register or login before being allowed to play.")] public bool RequireLogin; - - [Description( - "Disables Invisibility potions from being used in PvP (Note, they can use them on the client, but the effect isn't sent to the rest of the server)" - )] public bool DisableInvisPvP; - - [Description("The maximum distance players disabled for various reasons can move from")] public int - MaxRangeForDisabled = 10; - - [Description("Server password required to join server")] public string ServerPassword = ""; - - [Description("Protect chests with region and build permissions")] public bool RegionProtectChests; - - [Description("Disable users from being able to login with account password when joining")] public bool - DisableLoginBeforeJoin; - - [Description("Allows users to register any username with /register")] public bool AllowRegisterAnyUsername; - - [Description("Allows users to login with any username with /login")] public bool AllowLoginAnyUsername = true; - - [Description("The maximum damage a player/npc can inflict")] public int MaxDamage = 175; - - [Description("The maximum damage a projectile can inflict")] public int MaxProjDamage = 175; - - [Description("Ignores checking to see if player 'can' update a projectile")] public bool IgnoreProjUpdate = false; - - [Description("Ignores checking to see if player 'can' kill a projectile")] public bool IgnoreProjKill = false; - - [Description("Ignores all no clip checks for players")] public bool IgnoreNoClip = false; - - [Description("Allow Ice placement even when user does not have canbuild")] public bool AllowIce = false; - - public static ConfigFile Read(string path) - { - if (!File.Exists(path)) - return new ConfigFile(); - using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - return Read(fs); - } - } - - public static ConfigFile Read(Stream stream) - { - using (var sr = new StreamReader(stream)) - { - var cf = JsonConvert.DeserializeObject(sr.ReadToEnd()); - if (ConfigRead != null) - ConfigRead(cf); - return cf; - } - } - - public void Write(string path) - { - using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write)) - { - Write(fs); - } - } - - public void Write(Stream stream) - { - var str = JsonConvert.SerializeObject(this, Formatting.Indented); - using (var sw = new StreamWriter(stream)) - { - sw.Write(str); - } - } - - public static Action ConfigRead; - - - public static void DumpDescriptions() - { - var sb = new StringBuilder(); - var defaults = new ConfigFile(); - - foreach (var field in defaults.GetType().GetFields().OrderBy(f => f.Name)) - { - if (field.IsStatic) - continue; - - var name = field.Name; - var type = field.FieldType.Name; - - var descattr = - field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute; - var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None"; - - var def = field.GetValue(defaults); - - sb.AppendLine("## {0} ".SFormat(name)); - sb.AppendLine("**Type:** {0} ".SFormat(type)); - sb.AppendLine("**Description:** {0} ".SFormat(desc)); - sb.AppendLine("**Default:** \"{0}\" ".SFormat(def)); - sb.AppendLine(); - } - - File.WriteAllText("ConfigDescriptions.txt", sb.ToString()); - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace TShockAPI +{ + public class ConfigFile + { + [Description( + "The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))" + )] public int InvasionMultiplier = 1; + + [Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")] public int + DefaultMaximumSpawns = 5; + + [Description("The delay between waves. Shorter values lead to less mobs.")] public int DefaultSpawnRate = 600; + [Description("The port the server runs on.")] public int ServerPort = 7777; + [Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")] public bool EnableWhitelist; + + [Description( + "Enable the ability for invaison size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn que for the map." + )] public bool InfiniteInvasion; + + [Description("Set the server pvp mode. Vaild types are, \"normal\", \"always\", \"disabled\"")] public string PvPMode + = "normal"; + + [Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")] public bool + SpawnProtection = true; + + [Description("Radius from spawn tile for SpawnProtection.")] public int SpawnProtectionRadius = 10; + + [Description( + "Max slots for the server. If you want people to be kicked with \"Server is full\" set this to how many players you want max and then set Terraria max players to 2 higher." + )] public int MaxSlots = 8; + + [Description("Global protection agent for any block distance based anti-grief check.")] public bool RangeChecks = true; + [Description("Disables any building; placing of blocks")] public bool DisableBuild; + + [Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")] public float[] + SuperAdminChatRGB = {255, 0, 0}; + + [Description("Super admin group chat prefix")] public string SuperAdminChatPrefix = "(Admin) "; + [Description("Super admin group chat suffix")] public string SuperAdminChatSuffix = ""; + + [Description( + "Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")] public int BackupInterval; + + [Description("How long backups are kept in minutes. 2880 = 2 days.")] public int BackupKeepFor = 60; + + [Description( + "Remembers where a player left off. It works by remembering the IP, NOT the character. \neg. When you try to disconnect, and reconnect to be automatically placed at spawn, you'll be at your last location. Note: Won't save after server restarts." + )] public bool RememberLeavePos; + + [Description("Hardcore players ONLY. This means softcore players cannot join.")] public bool HardcoreOnly; + [Description("Mediumcore players ONLY. This means softcore players cannot join.")] public bool MediumcoreOnly; + [Description("Kicks a Hardcore player on death.")] public bool KickOnMediumcoreDeath; + [Description("Bans a Hardcore player on death.")] public bool BanOnMediumcoreDeath; + + [Description("Enable/Disable Terrarias built in auto save")] public bool AutoSave = true; + + [Description("Number of failed login attempts before kicking the player.")] public int MaximumLoginAttempts = 3; + + [Description("Not implemented")] public string RconPassword = ""; + [Description("Not implemented")] public int RconPort = 7777; + + [Description("Used when replying to a rest /status request.")] public string ServerName = ""; + [Description("Not implemented")] public string MasterServer = "127.0.0.1"; + + [Description("Valid types are \"sqlite\" and \"mysql\"")] public string StorageType = "sqlite"; + + [Description("The MySQL Hostname and port to direct connections to")] public string MySqlHost = "localhost:3306"; + [Description("Database name to connect to")] public string MySqlDbName = ""; + [Description("Database username to connect with")] public string MySqlUsername = ""; + [Description("Database password to connect with")] public string MySqlPassword = ""; + + [Description("Bans a Mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban"; + [Description("Kicks a Mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick"; + + [Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")] public bool + EnableDNSHostResolution; + + [Description("Enables kicking of banned users by matching their IP Address")] public bool EnableIPBans = true; + + [Description("Enables kicking of banned users by matching their Character Name")] public bool EnableBanOnUsernames; + + [Description("Selects the default group name to place new registrants under")] public string + DefaultRegistrationGroupName = "default"; + + [Description("Selects the default group name to place non registered users under")] public string + DefaultGuestGroupName = "guest"; + + [Description("Force-Disable printing logs to players with the log permission")] public bool DisableSpewLogs = true; + + [Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms")] public string HashAlgorithm = "sha512"; + + [Description("Buffers up the packets and sends them out at the end of each frame")] public bool BufferPackets = true; + + [Description("String that is used when kicking people when the server is full.")] public string ServerFullReason = + "Server is full"; + + [Description("String that is used when kicking people when the server is full with no reserved slots.")] public string + ServerFullNoReservedReason = "Server is full. No reserved slots open."; + + [Description("This will save the world if Terraria crashes from an unhandled exception.")] public bool + SaveWorldOnCrash = true; + + [Description("This will announce a player's location on join")] public bool EnableGeoIP; + + [Description("This will turn on a token requirement for the /status API endpoint.")] public bool + EnableTokenEndpointAuthentication; + + [Description("This is used when the API endpoint /status is queried.")] public string ServerNickname = "TShock Server"; + + [Description("Enable/Disable the rest api.")] public bool RestApiEnabled; + + [Description("This is the port which the rest api will listen on.")] public int RestApiPort = 7878; + + [Description("Disable tombstones for all players.")] public bool DisableTombstones = true; + + [Description("Displays a player's IP on join to everyone who has the log permission")] public bool DisplayIPToAdmins; + + [Description( + "Some tiles are 'fixed' by not letting TShock handle them. Disabling this may break certain asthetic tiles.")] public + bool EnableInsecureTileFixes = true; + + [Description("Kicks users using a proxy as identified with the GeoIP database")] public bool KickProxyUsers = true; + + [Description("Disables hardmode, can't never be activated. Overrides /starthardmode")] public bool DisableHardmode; + + [Description("Disables Dungeon Guardian from being spawned by player packets, this will instead force a respawn")] public bool DisableDungeonGuardian; + + [Description("Enable Server Side Inventory checks, EXPERIMENTAL")] public bool ServerSideInventory; + + [Description("How often SSI should save, in minutes")] public int ServerSideInventorySave = 15; + + [Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON")] public int LogonDiscardThreshold=250; + + [Description("Disables reporting of playercount to the stat system.")] public bool DisablePlayerCountReporting; + + [Description("Disables clown bomb projectiles from spawning")] public bool DisableClownBombs; + + [Description("Disables snow ball projectiles from spawning")] public bool DisableSnowBalls; + + [Description( + "Change ingame chat format, {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message" + )] public string ChatFormat = "{1}{2}{3}: {4}"; + + [Description("Force the world time to be normal, day, or night")] public string ForceTime = "normal"; + + [Description("Disable/Revert a player if they exceed this number of tile kills within 1 second.")] public int + TileKillThreshold = 60; + + [Description("Disable/Revert a player if they exceed this number of tile places within 1 second.")] public int + TilePlaceThreshold = 20; + + [Description("Disable a player if they exceed this number of liquid sets within 1 second.")] public int + TileLiquidThreshold = 15; + + [Description("Disable a player if they exceed this number of projectile new within 1 second.")] public int + ProjectileThreshold = 50; + + [Description("Ignore shrapnel from crystal bullets for Projectile Threshold.")] public bool + ProjIgnoreShrapnel = true; + + [Description("Require all players to register or login before being allowed to play.")] public bool RequireLogin; + + [Description( + "Disables Invisibility potions from being used in PvP (Note, they can use them on the client, but the effect isn't sent to the rest of the server)" + )] public bool DisableInvisPvP; + + [Description("The maximum distance players disabled for various reasons can move from")] public int + MaxRangeForDisabled = 10; + + [Description("Server password required to join server")] public string ServerPassword = ""; + + [Description("Protect chests with region and build permissions")] public bool RegionProtectChests; + + [Description("Disable users from being able to login with account password when joining")] public bool + DisableLoginBeforeJoin; + + [Description("Allows users to register any username with /register")] public bool AllowRegisterAnyUsername; + + [Description("Allows users to login with any username with /login")] public bool AllowLoginAnyUsername = true; + + [Description("The maximum damage a player/npc can inflict")] public int MaxDamage = 175; + + [Description("The maximum damage a projectile can inflict")] public int MaxProjDamage = 175; + + [Description("Ignores checking to see if player 'can' update a projectile")] public bool IgnoreProjUpdate = false; + + [Description("Ignores checking to see if player 'can' kill a projectile")] public bool IgnoreProjKill = false; + + [Description("Ignores all no clip checks for players")] public bool IgnoreNoClip = false; + + [Description("Allow Ice placement even when user does not have canbuild")] public bool AllowIce = false; + + public static ConfigFile Read(string path) + { + if (!File.Exists(path)) + return new ConfigFile(); + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + return Read(fs); + } + } + + public static ConfigFile Read(Stream stream) + { + using (var sr = new StreamReader(stream)) + { + var cf = JsonConvert.DeserializeObject(sr.ReadToEnd()); + if (ConfigRead != null) + ConfigRead(cf); + return cf; + } + } + + public void Write(string path) + { + using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write)) + { + Write(fs); + } + } + + public void Write(Stream stream) + { + var str = JsonConvert.SerializeObject(this, Formatting.Indented); + using (var sw = new StreamWriter(stream)) + { + sw.Write(str); + } + } + + public static Action ConfigRead; + + + public static void DumpDescriptions() + { + var sb = new StringBuilder(); + var defaults = new ConfigFile(); + + foreach (var field in defaults.GetType().GetFields().OrderBy(f => f.Name)) + { + if (field.IsStatic) + continue; + + var name = field.Name; + var type = field.FieldType.Name; + + var descattr = + field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute; + var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : "None"; + + var def = field.GetValue(defaults); + + sb.AppendLine("## {0} ".SFormat(name)); + sb.AppendLine("**Type:** {0} ".SFormat(type)); + sb.AppendLine("**Description:** {0} ".SFormat(desc)); + sb.AppendLine("**Default:** \"{0}\" ".SFormat(def)); + sb.AppendLine(); + } + + File.WriteAllText("ConfigDescriptions.txt", sb.ToString()); + } + } } \ No newline at end of file diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs index bc4462286..8b3423ccf 100644 --- a/TShockAPI/DB/BanManager.cs +++ b/TShockAPI/DB/BanManager.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs index 25391bf29..c384cf664 100644 --- a/TShockAPI/DB/RegionManager.cs +++ b/TShockAPI/DB/RegionManager.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index 8f3c93d4b..ac4dfd31d 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -1,119 +1,119 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.IO; - -namespace TShockAPI -{ - public class FileTools - { - internal static string RulesPath - { - get { return Path.Combine(TShock.SavePath, "rules.txt"); } - } - - internal static string MotdPath - { - get { return Path.Combine(TShock.SavePath, "motd.txt"); } - } - - internal static string WhitelistPath - { - get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } - } - - internal static string RememberedPosPath - { - get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } - } - - internal static string ConfigPath - { - get { return Path.Combine(TShock.SavePath, "config.json"); } - } - - public static void CreateFile(string file) - { - File.Create(file).Close(); - } - - public static void CreateIfNot(string file, string data = "") - { - if (!File.Exists(file)) - { - File.WriteAllText(file, data); - } - } - - /// - /// Sets up the configuration file for all variables, and creates any missing files. - /// - public static void SetupConfig() - { - if (!Directory.Exists(TShock.SavePath)) - { - Directory.CreateDirectory(TShock.SavePath); - } - - CreateIfNot(RulesPath, "Respect the admins!\nDon't use TNT!"); - CreateIfNot(MotdPath, - "This server is running TShock for Terraria.\n Type /help for a list of commands.\n%255,000,000%Current map: %map%\nCurrent players: %players%"); - CreateIfNot(WhitelistPath); - if (File.Exists(ConfigPath)) - { - TShock.Config = ConfigFile.Read(ConfigPath); - // Add all the missing config properties in the json file - } - TShock.Config.Write(ConfigPath); - - } - - /// - /// Tells if a user is on the whitelist - /// - /// string ip of the user - /// true/false - public static bool OnWhitelist(string ip) - { - if (!TShock.Config.EnableWhitelist) - { - return true; - } - CreateIfNot(WhitelistPath, "127.0.0.1"); - using (var tr = new StreamReader(WhitelistPath)) - { - string whitelist = tr.ReadToEnd(); - ip = TShock.Utils.GetRealIP(ip); - bool contains = whitelist.Contains(ip); - if (!contains) - { - foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray())) - { - if (string.IsNullOrWhiteSpace(line)) - continue; - contains = TShock.Utils.GetIPv4Address(line).Equals(ip); - if (contains) - return true; - } - return false; - } - return true; - } - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.IO; + +namespace TShockAPI +{ + public class FileTools + { + internal static string RulesPath + { + get { return Path.Combine(TShock.SavePath, "rules.txt"); } + } + + internal static string MotdPath + { + get { return Path.Combine(TShock.SavePath, "motd.txt"); } + } + + internal static string WhitelistPath + { + get { return Path.Combine(TShock.SavePath, "whitelist.txt"); } + } + + internal static string RememberedPosPath + { + get { return Path.Combine(TShock.SavePath, "oldpos.xml"); } + } + + internal static string ConfigPath + { + get { return Path.Combine(TShock.SavePath, "config.json"); } + } + + public static void CreateFile(string file) + { + File.Create(file).Close(); + } + + public static void CreateIfNot(string file, string data = "") + { + if (!File.Exists(file)) + { + File.WriteAllText(file, data); + } + } + + /// + /// Sets up the configuration file for all variables, and creates any missing files. + /// + public static void SetupConfig() + { + if (!Directory.Exists(TShock.SavePath)) + { + Directory.CreateDirectory(TShock.SavePath); + } + + CreateIfNot(RulesPath, "Respect the admins!\nDon't use TNT!"); + CreateIfNot(MotdPath, + "This server is running TShock for Terraria.\n Type /help for a list of commands.\n%255,000,000%Current map: %map%\nCurrent players: %players%"); + CreateIfNot(WhitelistPath); + if (File.Exists(ConfigPath)) + { + TShock.Config = ConfigFile.Read(ConfigPath); + // Add all the missing config properties in the json file + } + TShock.Config.Write(ConfigPath); + + } + + /// + /// Tells if a user is on the whitelist + /// + /// string ip of the user + /// true/false + public static bool OnWhitelist(string ip) + { + if (!TShock.Config.EnableWhitelist) + { + return true; + } + CreateIfNot(WhitelistPath, "127.0.0.1"); + using (var tr = new StreamReader(WhitelistPath)) + { + string whitelist = tr.ReadToEnd(); + ip = TShock.Utils.GetRealIP(ip); + bool contains = whitelist.Contains(ip); + if (!contains) + { + foreach (var line in whitelist.Split(Environment.NewLine.ToCharArray())) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + contains = TShock.Utils.GetIPv4Address(line).Equals(ip); + if (contains) + return true; + } + return false; + } + return true; + } + } + } } \ No newline at end of file diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 051f5ccd8..db514d10f 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1,2704 +1,2704 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.IO.Streams; -using System.Linq; -using System.Text; -using Terraria; -using TShockAPI.Net; - -namespace TShockAPI -{ - public delegate bool GetDataHandlerDelegate(GetDataHandlerArgs args); - - public class GetDataHandlerArgs : EventArgs - { - public TSPlayer Player { get; private set; } - public MemoryStream Data { get; private set; } - - public Player TPlayer - { - get { return Player.TPlayer; } - } - - public GetDataHandlerArgs(TSPlayer player, MemoryStream data) - { - Player = player; - Data = data; - } - } - - public static class GetDataHandlers - { - private static Dictionary GetDataHandlerDelegates; - public static int[] WhitelistBuffMaxTime; - #region Events - - /// - /// Used when a TileEdit event is called. - /// - public class TileEditEventArgs : HandledEventArgs - { - /// - /// The TSPlayer who made the tile edit - /// - public TSPlayer Player { get; set; } - - /// - /// The tile coordinate on the X plane - /// - public int X { get; set; } - - /// - /// The tile coordinate on the Y plane - /// - public int Y { get; set; } - - /// - /// The Tile ID being edited. - /// - public byte Type { get; set; } - /// - /// The EditType. - /// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6) - /// - public byte EditType { get; set; } - } - - /// - /// TileEdit - called when a tile is placed or destroyed - /// - public static HandlerList TileEdit; - private static bool OnTileEdit(TSPlayer ply, int x, int y, byte type, byte editType) - { - if (TileEdit == null) - return false; - - var args = new TileEditEventArgs - { - Player = ply, - X = x, - Y = y, - Type = type, - EditType = editType - }; - TileEdit.Invoke(null, args); - return args.Handled; - } - /// - /// For use in a TogglePvp event - /// - public class TogglePvpEventArgs : HandledEventArgs - { - /// - /// The Terraria player ID of the player - /// - public byte PlayerId { get; set; } - /// - /// Enable/disable pvp? - /// - public bool Pvp { get; set; } - } - /// - /// TogglePvp - called when a player toggles pvp - /// - public static HandlerList TogglePvp; - private static bool OnPvpToggled(byte _id, bool _pvp) - { - if (TogglePvp == null) - return false; - - var args = new TogglePvpEventArgs - { - PlayerId = _id, - Pvp = _pvp, - }; - TogglePvp.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerSlot event - /// - public class PlayerSlotEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID - /// - public byte PlayerId { get; set; } - /// - /// The slot edited - /// - public byte Slot { get; set; } - /// - /// The stack edited - /// - public byte Stack { get; set; } - /// - /// The item prefix - /// - public byte Prefix { get; set; } - /// - /// Item type - /// - public short Type { get; set; } - } - /// - /// PlayerSlot - called at a PlayerSlot event - /// - public static HandlerList PlayerSlot; - private static bool OnPlayerSlot(byte _plr, byte _slot, byte _stack, byte _prefix, short _type) - { - if (PlayerSlot == null) - return false; - - var args = new PlayerSlotEventArgs - { - PlayerId = _plr, - Slot = _slot, - Stack = _stack, - Prefix = _prefix, - Type = _type - }; - PlayerSlot.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerHP event - /// - public class PlayerHPEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte PlayerId { get; set; } - /// - /// Current HP - /// - public short Current { get; set; } - /// - /// Maximum HP - /// - public short Max { get; set; } - } - /// - /// PlayerHP - called at a PlayerHP event - /// - public static HandlerList PlayerHP; - - private static bool OnPlayerHP(byte _plr, short _cur, short _max) - { - if (PlayerHP == null) - return false; - - var args = new PlayerHPEventArgs - { - PlayerId = _plr, - Current = _cur, - Max = _max, - }; - PlayerHP.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerMana event - /// - public class PlayerManaEventArgs : HandledEventArgs - { - public byte PlayerId { get; set; } - public short Current { get; set; } - public short Max { get; set; } - } - /// - /// PlayerMana - called at a PlayerMana event - /// - public static HandlerList PlayerMana; - - private static bool OnPlayerMana(byte _plr, short _cur, short _max) - { - if (PlayerMana == null) - return false; - - var args = new PlayerManaEventArgs - { - PlayerId = _plr, - Current = _cur, - Max = _max, - }; - PlayerMana.Invoke(null, args); - return args.Handled; - } - - public class PlayerInfoEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte PlayerId { get; set; } - /// - /// Hair color - /// - public byte Hair { get; set; } - /// - /// Gender (male = true) - /// - public bool Male { get; set; } - /// - /// Character difficulty - /// - public byte Difficulty { get; set; } - /// - /// Player/character name - /// - public string Name { get; set; } - } - /// - /// PlayerInfo - called at a PlayerInfo event - /// If this is cancelled, the server will ForceKick the player. If this should be changed in the future, let someone know. - /// - public static HandlerList PlayerInfo; - - private static bool OnPlayerInfo(byte _plrid, byte _hair, bool _male, byte _difficulty, string _name) - { - if (PlayerInfo == null) - return false; - - var args = new PlayerInfoEventArgs - { - PlayerId = _plrid, - Hair = _hair, - Male = _male, - Difficulty = _difficulty, - Name = _name, - }; - PlayerInfo.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a TileKill event - /// - public class TileKillEventArgs : HandledEventArgs - { - /// - /// The X coordinate that is being killed - /// - public int TileX { get; set; } - /// - /// The Y coordinate that is being killed - /// - public int TileY { get; set; } - } - /// - /// TileKill - When a tile is removed fromt he world - /// - public static HandlerList TileKill; - - private static bool OnTileKill(int tilex, int tiley) - { - if (TileKill == null) - return false; - - var args = new TileKillEventArgs - { - TileX = tilex, - TileY = tiley, - }; - TileKill.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a KillMe event - /// - public class KillMeEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte PlayerId { get; set; } - /// - /// The direction the damage is coming from (?) - /// - public byte Direction { get; set; } - /// - /// Amount of damage delt - /// - public short Damage { get; set; } - /// - /// Player's current pvp setting - /// - public bool Pvp { get; set; } - } - /// - /// KillMe - Terraria's crappy way of handling damage from players - /// - public static HandlerList KillMe; - - private static bool OnKillMe(byte plr, byte direction, short damage, bool pvp) - { - if (KillMe == null) - return false; - - var args = new KillMeEventArgs - { - PlayerId = plr, - Direction = direction, - Damage = damage, - Pvp = pvp, - }; - KillMe.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerUpdate event - /// - public class PlayerUpdateEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte PlayerId { get; set; } - /// - /// ??? - /// - public byte Control { get; set; } - /// - /// Current item? - /// - public byte Item { get; set; } - /// - /// Position of the player - /// - public Vector2 Position { get; set; } - /// - /// Velocity of the player - /// - public Vector2 Velocity { get; set; } - } - /// - /// PlayerUpdate - When the player sends it's updated information to the server - /// - public static HandlerList PlayerUpdate; - - private static bool OnPlayerUpdate(byte player, byte control, byte item, Vector2 position, Vector2 velocity) - { - if (PlayerUpdate == null) - return false; - - var args = new PlayerUpdateEventArgs - { - PlayerId = player, - Control = control, - Item = item, - Position = position, - Velocity = velocity, - }; - PlayerUpdate.Invoke(null, args); - return args.Handled; - } - public static bool TSCheckNoclip(Vector2 Position, int Width, int Height) - { - int num = (int)(Position.X / 16f) - 1; - int num2 = (int)((Position.X + (float)Width) / 16f) + 2; - int num3 = (int)(Position.Y / 16f) - 1; - int num4 = (int)((Position.Y + (float)Height) / 16f) + 2; - if (num < 0) - { - num = 0; - } - if (num2 > Main.maxTilesX) - { - num2 = Main.maxTilesX; - } - if (num3 < 0) - { - num3 = 0; - } - if (num4 > Main.maxTilesY) - { - num4 = Main.maxTilesY; - } - for (int i = num; i < num2; i++) - { - for (int j = num3; j < num4; j++) - { - if (Main.tile[i, j] != null && Main.tile[i, j].active && Main.tileSolid[(int)Main.tile[i, j].type] && !Main.tileSolidTop[(int)Main.tile[i, j].type] &&(((int)Main.tile[i,j].type !=53) && ((int)Main.tile[i,j].type !=112) && ((int)Main.tile[i,j].type !=116) && ((int)Main.tile[i,j].type !=123)) && ((Main.tile[i,j].liquid == 0 )&& !Main.tile[i,j].lava)) - { - Vector2 vector; - vector.X = (float)(i * 16); - vector.Y = (float)(j * 16); - if (Position.X + (float)Width > vector.X && Position.X < vector.X + 16f && Position.Y + (float)Height > vector.Y && Position.Y < vector.Y + 16f) - { - return true; - } - } - } - } - return false; - } - - /// - /// For use in a SendTileSquare event - /// - public class SendTileSquareEventArgs : HandledEventArgs - { - /// - /// Size of the area - /// - public short Size { get; set; } - /// - /// A corner of the section - /// - public int TileX { get; set; } - /// - /// A corner of the section - /// - public int TileY { get; set; } - } - /// - /// SendTileSquare - When the player sends a tile square - /// - public static HandlerList SendTileSquare; - - private static bool OnSendTileSquare(short size, int tilex, int tiley) - { - if (SendTileSquare == null) - return false; - - var args = new SendTileSquareEventArgs - { - Size = size, - TileX = tilex, - TileY = tiley, - }; - SendTileSquare.Invoke(null, args); - return args.Handled; - } - /// - /// For use in a NewProjectile event - /// - public class NewProjectileEventArgs : HandledEventArgs - { - /// - /// ??? - /// - public short Identity { get; set; } - /// - /// Location of the projectile - /// - public Vector2 Position { get; set; } - /// - /// Velocity of the projectile - /// - public Vector2 Velocity { get; set; } - /// - /// Knockback - /// - public float Knockback { get; set; } - /// - /// Damage from the projectile - /// - public short Damage { get; set; } - /// - /// Terraria playerID owner of the projectile - /// - public byte Owner { get; set; } - /// - /// Type of projectile - /// - public byte Type { get; set; } - /// - /// ??? - /// - public int Index { get; set; } - } - /// - /// NewProjectile - Called when a client creates a new projectile - /// - public static HandlerList NewProjectile; - - private static bool OnNewProjectile(short ident, Vector2 pos, Vector2 vel, float knockback, short dmg, byte owner, byte type, int index) - { - if (NewProjectile == null) - return false; - - var args = new NewProjectileEventArgs - { - Identity = ident, - Position = pos, - Velocity = vel, - Knockback = knockback, - Damage = dmg, - Owner = owner, - Type = type, - Index = index, - }; - NewProjectile.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a LiquidSet event - /// - public class LiquidSetEventArgs : HandledEventArgs - { - /// - /// X location of the tile - /// - public int TileX { get; set; } - /// - /// Y location of the tile - /// - public int TileY { get; set; } - /// - /// ??? - /// - public byte Liquid { get; set;} - /// - /// True if lava - /// - public bool Lava { get; set; } - } - /// - /// LiquidSet - When ever a liquid is set - /// - public static HandlerList LiquidSet; - - private static bool OnLiquidSet(int tilex, int tiley, byte liquid, bool lava) - { - if (LiquidSet == null) - return false; - - var args = new LiquidSetEventArgs - { - TileX = tilex, - TileY = tiley, - Liquid = liquid, - Lava = lava, - }; - LiquidSet.Invoke(null, args); - return args.Handled; - } - /// - /// For use in a PlayerSpawn event - /// - public class SpawnEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte Player { get; set; } - /// - /// X location of the player's spawn - /// - public int SpawnX { get; set; } - /// - /// Y location of the player's spawn - /// - public int SpawnY { get; set; } - } - /// - /// PlayerSpawn - When a player spawns - /// - public static HandlerList PlayerSpawn; - - private static bool OnPlayerSpawn(byte player, int spawnX, int spawnY) - { - if (PlayerSpawn == null) - return false; - - var args = new SpawnEventArgs - { - Player = player, - SpawnX = spawnX, - SpawnY = spawnY, - }; - PlayerSpawn.Invoke(null, args); - return args.Handled; - } - /// - /// For use with a ChestOpen event - /// - public class ChestOpenEventArgs : HandledEventArgs - { - /// - /// X location of said chest - /// - public int X { get; set; } - /// - /// Y location of said chest - /// - public int Y { get; set; } - } - /// - /// ChestOpen - Called when any chest is opened - /// - public static HandlerList ChestOpen; - - private static bool OnChestOpen(int x, int y) - { - if (ChestOpen == null) - return false; - - var args = new ChestOpenEventArgs - { - X = x, - Y = y, - }; - ChestOpen.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a ChestItemChange event - /// - public class ChestItemEventArgs : HandledEventArgs - { - /// - /// ChestID - /// - public short ID { get; set; } - /// - /// Slot of the item - /// - public byte Slot { get; set; } - /// - /// How many? - /// - public byte Stacks { get; set; } - /// - /// Item prefix - /// - public byte Prefix { get; set; } - /// - /// Item type - /// - public short Type { get; set; } - } - /// - /// ChestItemChange - Called when an item in a chest changes - /// - public static HandlerList ChestItemChange; - - private static bool OnChestItemChange(short id, byte slot, byte stacks, byte prefix, short type) - { - if (ChestItemChange == null) - return false; - - var args = new ChestItemEventArgs - { - ID = id, - Slot = slot, - Stacks = stacks, - Prefix = prefix, - Type = type, - }; - ChestItemChange.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a Sign event - /// - public class SignEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public short ID { get; set; } - /// - /// X location of the sign - /// - public int X { get; set; } - /// - /// Y location of the sign - /// - public int Y { get; set; } - } - /// - /// Sign - Called when a sign is changed - /// - public static HandlerList Sign; - - private static bool OnSignEvent(short id, int x, int y) - { - if (Sign == null) - return false; - - var args = new SignEventArgs - { - ID = id, - X = x, - Y = y, - }; - Sign.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a NPCHome event - /// - public class NPCHomeChangeEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public short ID { get; set; } - /// - /// X location of the NPC home change - /// - public short X { get; set; } - /// - /// Y location of the NPC home change - /// - public short Y { get; set; } - /// - /// ByteBool homeless - /// - public byte Homeless { get; set; } - } - /// - /// NPCHome - Called when an NPC's home is changed - /// - public static HandlerList NPCHome; - - private static bool OnUpdateNPCHome(short id, short x, short y, byte homeless) - { - if (NPCHome == null) - return false; - - var args = new NPCHomeChangeEventArgs - { - ID = id, - X = x, - Y = y, - Homeless = homeless, - }; - NPCHome.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerBuff event - /// - public class PlayerBuffEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte ID { get; set; } - /// - /// Buff Type - /// - public byte Type { get; set; } - /// - /// Time the buff lasts - /// - public short Time { get; set; } - } - /// - /// PlayerBuff - Called when a player is buffed - /// - public static HandlerList PlayerBuff; - - private static bool OnPlayerBuff(byte id, byte type, short time) - { - if (PlayerBuff == null) - return false; - - var args = new PlayerBuffEventArgs - { - ID = id, - Type = type, - Time = time, - }; - PlayerBuff.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in an ItemDrop event - /// - public class ItemDropEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public short ID { get; set; } - /// - /// Position of the item - /// - public Vector2 Position { get; set; } - /// - /// Velocity at which the item is deployed - /// - public Vector2 Velocity { get; set; } - /// - /// Stacks - /// - public byte Stacks { get; set; } - /// - /// Prefix of the item - /// - public byte Prefix { get; set; } - /// - /// Item type - /// - public short Type { get; set; } - } - /// - /// ItemDrop - Called when an item is dropped - /// - public static HandlerList ItemDrop; - - private static bool OnItemDrop(short id, Vector2 pos, Vector2 vel, byte stacks, byte prefix, short type) - { - if (ItemDrop == null) - return false; - - var args = new ItemDropEventArgs - { - ID = id, - Position = pos, - Velocity = vel, - Stacks = stacks, - Prefix = prefix, - Type = type, - }; - ItemDrop.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerDamage event - /// - public class PlayerDamageEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte ID { get; set; } - /// - /// The direction the damage is occuring from - /// - public byte Direction { get; set; } - /// - /// Amount of damage - /// - public short Damage { get; set; } - /// - /// If the player has PVP on - /// - public byte PVP { get; set; } - /// - /// Is the damage critical? - /// - public byte Critical { get; set; } - } - /// - /// PlayerDamage - Called when a player is damaged - /// - public static HandlerList PlayerDamage; - - private static bool OnPlayerDamage(byte id, byte dir, short dmg, byte pvp, byte crit) - { - if (PlayerDamage == null) - return false; - - var args = new PlayerDamageEventArgs - { - ID = id, - Direction = dir, - Damage = dmg, - PVP = pvp, - Critical = crit, - }; - PlayerDamage.Invoke(null, args); - return args.Handled; - } - - /// - /// For use with a NPCStrike event - /// - public class NPCStrikeEventArgs : HandledEventArgs - { - /// - /// ??? - /// - public byte ID { get; set; } - /// - /// Direction the damage occurred from - /// - public byte Direction { get; set; } - /// - /// Amount of damage - /// - public short Damage { get; set; } - /// - /// Is PVP enabled...? - /// - public byte PVP { get; set; } - /// - /// Critical? - /// - public byte Critical { get; set; } - } - /// - /// NPCStrike - Called when an NPC is attacked - /// - public static HandlerList NPCStrike; - - private static bool OnNPCStrike(byte id, byte dir, short dmg, byte pvp, byte crit) - { - if (NPCStrike == null) - return false; - - var args = new NPCStrikeEventArgs - { - ID = id, - Direction = dir, - Damage = dmg, - PVP = pvp, - Critical = crit, - }; - NPCStrike.Invoke(null, args); - return args.Handled; - } - - /// - /// For use with a NPCSpecial event - /// - public class NPCSpecialEventArgs : HandledEventArgs - { - /// - /// ??? - /// - public byte ID { get; set; } - /// - /// Type...? - /// - public byte Type { get; set; } - } - /// - /// NPCSpecial - Called at some point - /// - public static HandlerList NPCSpecial; - - private static bool OnNPCSpecial(byte id, byte type) - { - if (NPCSpecial == null) - return false; - - var args = new NPCSpecialEventArgs - { - ID = id, - Type = type, - }; - NPCSpecial.Invoke(null, args); - return args.Handled; - } - - /// - /// For use with a PlayerAnimation event - /// - public class PlayerAnimationEventArgs : HandledEventArgs - { - } - - /// - /// PlayerAnimation - Called when a player animates - /// - public static HandlerList PlayerAnimation; - - private static bool OnPlayerAnimation() - { - if (PlayerAnimation == null) - return false; - - var args = new PlayerAnimationEventArgs {}; - PlayerAnimation.Invoke(null, args); - return args.Handled; - } - - /// - /// For use in a PlayerBuffUpdate event - /// - public class PlayerBuffUpdateEventArgs : HandledEventArgs - { - /// - /// The Terraria playerID of the player - /// - public byte ID { get; set; } - } - /// - /// PlayerBuffUpdate - Called when a player updates buffs - /// - public static HandlerList PlayerBuffUpdate; - - private static bool OnPlayerBuffUpdate(byte id) - { - if (PlayerBuffUpdate == null) - return false; - - var args = new PlayerBuffUpdateEventArgs - { - ID = id, - }; - PlayerBuffUpdate.Invoke(null, args); - return args.Handled; - } - - #endregion - public static void InitGetDataHandler() - { - #region Blacklists - - WhitelistBuffMaxTime = new int[Main.maxBuffs]; - WhitelistBuffMaxTime[20] = 600; - WhitelistBuffMaxTime[0x18] = 1200; - WhitelistBuffMaxTime[0x1f] = 120; - WhitelistBuffMaxTime[0x27] = 420; - - #endregion Blacklists - - GetDataHandlerDelegates = new Dictionary - { - {PacketTypes.PlayerInfo, HandlePlayerInfo}, - {PacketTypes.PlayerUpdate, HandlePlayerUpdate}, - {PacketTypes.Tile, HandleTile}, - {PacketTypes.TileSendSquare, HandleSendTileSquare}, - {PacketTypes.ProjectileNew, HandleProjectileNew}, - {PacketTypes.TogglePvp, HandleTogglePvp}, - {PacketTypes.TileKill, HandleTileKill}, - {PacketTypes.PlayerKillMe, HandlePlayerKillMe}, - {PacketTypes.LiquidSet, HandleLiquidSet}, - {PacketTypes.PlayerSpawn, HandleSpawn}, - {PacketTypes.ChestGetContents, HandleChestOpen}, - {PacketTypes.ChestItem, HandleChestItem}, - {PacketTypes.SignNew, HandleSign}, - {PacketTypes.PlayerSlot, HandlePlayerSlot}, - {PacketTypes.TileGetSection, HandleGetSection}, - {PacketTypes.UpdateNPCHome, UpdateNPCHome}, - {PacketTypes.PlayerAddBuff, HandlePlayerBuff}, - {PacketTypes.ItemDrop, HandleItemDrop}, - {PacketTypes.PlayerHp, HandlePlayerHp}, - {PacketTypes.PlayerMana, HandlePlayerMana}, - {PacketTypes.PlayerDamage, HandlePlayerDamage}, - {PacketTypes.NpcStrike, HandleNpcStrike}, - {PacketTypes.NpcSpecial, HandleSpecial}, - {PacketTypes.PlayerAnimation, HandlePlayerAnimation}, - {PacketTypes.PlayerBuff, HandlePlayerBuffUpdate}, - {PacketTypes.PasswordSend, HandlePassword}, - {PacketTypes.ContinueConnecting2, HandleConnecting}, - {PacketTypes.ProjectileDestroy, HandleProjectileKill}, - {PacketTypes.SpawnBossorInvasion, HandleSpawnBoss} - }; - } - - public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data) - { - GetDataHandlerDelegate handler; - if (GetDataHandlerDelegates.TryGetValue(type, out handler)) - { - try - { - return handler(new GetDataHandlerArgs(player, data)); - } - catch (Exception ex) - { - Log.Error(ex.ToString()); - } - } - return false; - } - - private static bool HandlePlayerSlot(GetDataHandlerArgs args) - { - byte plr = args.Data.ReadInt8(); - byte slot = args.Data.ReadInt8(); - byte stack = args.Data.ReadInt8(); - byte prefix = args.Data.ReadInt8(); - short type = args.Data.ReadInt16(); - - if (OnPlayerSlot(plr, slot, stack, prefix, type)) - return true; - - if (plr != args.Player.Index) - { - return true; - } - - if (slot < 0 || slot > NetItem.maxNetInventory) - { - return true; - } - - var item = new Item(); - item.netDefaults(type); - item.Prefix(prefix); - - if (args.Player.IsLoggedIn) - { - args.Player.PlayerData.StoreSlot(slot, type, prefix, stack); - } - - return false; - } - - public static bool HandlePlayerHp(GetDataHandlerArgs args) - { - var plr = args.Data.ReadInt8(); - var cur = args.Data.ReadInt16(); - var max = args.Data.ReadInt16(); - - if (OnPlayerHP(plr, cur, max)) - return true; - - if (args.Player.FirstMaxHP == 0) - args.Player.FirstMaxHP = max; - - if (max > 400 && max > args.Player.FirstMaxHP) - { - TShock.Utils.ForceKick(args.Player, "Hacked Client Detected."); - return false; - } - - if (args.Player.IsLoggedIn) - { - args.Player.PlayerData.maxHealth = max; - } - - return false; - } - - private static bool HandlePlayerMana(GetDataHandlerArgs args) - { - var plr = args.Data.ReadInt8(); - var cur = args.Data.ReadInt16(); - var max = args.Data.ReadInt16(); - - if (OnPlayerMana(plr, cur, max)) - return true; - - if (args.Player.FirstMaxMP == 0) - args.Player.FirstMaxMP = max; - - if (max > 400 && max > args.Player.FirstMaxMP) - { - TShock.Utils.ForceKick(args.Player, "Hacked Client Detected."); - return false; - } - - return false; - } - - private static bool HandlePlayerInfo(GetDataHandlerArgs args) - { - var playerid = args.Data.ReadInt8(); - var hair = args.Data.ReadInt8(); - var male = args.Data.ReadBoolean(); - args.Data.Position += 21; - var difficulty = args.Data.ReadInt8(); - string name = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1))); - - if (OnPlayerInfo(playerid, hair, male, difficulty, name)) - { - TShock.Utils.ForceKick(args.Player, "A plugin cancelled the event."); - return true; - } - - /*if (!TShock.Utils.ValidString(name)) - { - TShock.Utils.ForceKick(args.Player, "Unprintable character in name"); - return true; - }*/ - if (name.Trim().Length == 0) - { - TShock.Utils.ForceKick(args.Player, "Empty Name."); - return true; - } - var ban = TShock.Bans.GetBanByName(name); - if (ban != null) - { - TShock.Utils.ForceKick(args.Player, string.Format("You are banned: {0}", ban.Reason)); - return true; - } - if (args.Player.ReceivedInfo) - { - return true; - } - if (TShock.Config.MediumcoreOnly && difficulty < 1) - { - TShock.Utils.ForceKick(args.Player, "Server is set to mediumcore and above characters only!"); - return true; - } - if (TShock.Config.HardcoreOnly && difficulty < 2) - { - TShock.Utils.ForceKick(args.Player, "Server is set to hardcore characters only!"); - return true; - } - args.Player.Difficulty = difficulty; - args.TPlayer.name = name; - args.Player.ReceivedInfo = true; - - return false; - } - - private static bool HandleConnecting(GetDataHandlerArgs args) - { - var user = TShock.Users.GetUserByName(args.Player.Name); - if (user != null && !TShock.Config.DisableLoginBeforeJoin) - { - args.Player.RequiresPassword = true; - NetMessage.SendData((int) PacketTypes.PasswordRequired, args.Player.Index); - return true; - } - else if (!string.IsNullOrEmpty(TShock.Config.ServerPassword)) - { - args.Player.RequiresPassword = true; - NetMessage.SendData((int) PacketTypes.PasswordRequired, args.Player.Index); - return true; - } - - if (args.Player.State == 1) - args.Player.State = 2; - NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); - return true; - } - - private static bool HandlePassword(GetDataHandlerArgs args) - { - if (!args.Player.RequiresPassword) - return true; - - string password = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1))); - var user = TShock.Users.GetUserByName(args.Player.Name); - if (user != null) - { - string encrPass = TShock.Utils.HashPassword(password); - if (user.Password.ToUpper() == encrPass.ToUpper()) - { - args.Player.RequiresPassword = false; - args.Player.PlayerData = TShock.InventoryDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name)); - - if (args.Player.State == 1) - args.Player.State = 2; - NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); - - var group = TShock.Utils.GetGroup(user.Group); - - if (TShock.Config.ServerSideInventory) - { - if (group.HasPermission(Permissions.bypassinventorychecks)) - { - args.Player.IgnoreActionsForClearingTrashCan = false; - } - else if (!TShock.CheckInventory(args.Player)) - { - args.Player.SendMessage("Login Failed, Please fix the above errors then /login again.", Color.Cyan); - args.Player.IgnoreActionsForClearingTrashCan = true; - return true; - } - } - - if (group.HasPermission(Permissions.ignorestackhackdetection)) - args.Player.IgnoreActionsForCheating = "none"; - - if (group.HasPermission(Permissions.usebanneditem)) - args.Player.IgnoreActionsForDisabledArmor = "none"; - - args.Player.Group = group; - args.Player.UserAccountName = args.Player.Name; - args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); - args.Player.IsLoggedIn = true; - args.Player.IgnoreActionsForInventory = "none"; - - if (!args.Player.IgnoreActionsForClearingTrashCan) - { - args.Player.PlayerData.CopyInventory(args.Player); - TShock.InventoryDB.InsertPlayerData(args.Player); - } - args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); - Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + args.Player.Name); - return true; - } - TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true); - return true; - } - if (!string.IsNullOrEmpty(TShock.Config.ServerPassword)) - { - if (TShock.Config.ServerPassword == password) - { - args.Player.RequiresPassword = false; - if (args.Player.State == 1) - args.Player.State = 2; - NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); - return true; - } - TShock.Utils.ForceKick(args.Player, "Incorrect Server Password"); - return true; - } - - TShock.Utils.ForceKick(args.Player, "Bad Password Attempt"); - return true; - } - - private static bool HandleGetSection(GetDataHandlerArgs args) - { - if (args.Player.RequestedSection) - return true; - - args.Player.RequestedSection = true; - if (TShock.HackedHealth(args.Player) && !args.Player.Group.HasPermission(Permissions.ignorestathackdetection)) - { - TShock.Utils.ForceKick(args.Player, "You have Hacked Health/Mana, Please use a different character."); - } - - if (!args.Player.Group.HasPermission(Permissions.ignorestackhackdetection)) - { - TShock.HackedInventory(args.Player); - } - - if (TShock.Utils.ActivePlayers() + 1 > TShock.Config.MaxSlots && - !args.Player.Group.HasPermission(Permissions.reservedslot)) - { - args.Player.SilentKickInProgress = true; - TShock.Utils.ForceKick(args.Player, TShock.Config.ServerFullReason); - return true; - } - - NetMessage.SendData((int) PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - - if (TShock.Config.EnableGeoIP && TShock.Geo != null) - { - Log.Info(string.Format("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", args.Player.Name, args.Player.IP, - args.Player.Group.Name, args.Player.Country, TShock.Utils.ActivePlayers(), - TShock.Config.MaxSlots)); - TShock.Utils.Broadcast(args.Player.Name + " has joined from the " + args.Player.Country, Color.Yellow); - } - else - { - Log.Info(string.Format("{0} ({1}) from '{2}' group joined. ({3}/{4})", args.Player.Name, args.Player.IP, - args.Player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); - TShock.Utils.Broadcast(args.Player.Name + " has joined", Color.Yellow); - } - - if (TShock.Config.DisplayIPToAdmins) - TShock.Utils.SendLogs(string.Format("{0} has joined. IP: {1}", args.Player.Name, args.Player.IP), Color.Blue); - - return false; - } - - private static bool HandleSendTileSquare(GetDataHandlerArgs args) - { - if (args.Player.Group.HasPermission(Permissions.allowclientsideworldedit)) - return false; - - var size = args.Data.ReadInt16(); - var tileX = args.Data.ReadInt32(); - var tileY = args.Data.ReadInt32(); - - if (OnSendTileSquare(size, tileX, tileY)) - return true; - - if (size > 5) - return true; - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY, size); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - var tiles = new NetTile[size,size]; - - for (int x = 0; x < size; x++) - { - for (int y = 0; y < size; y++) - { - tiles[x, y] = new NetTile(args.Data); - } - } - - bool changed = false; - for (int x = 0; x < size; x++) - { - int realx = tileX + x; - if (realx < 0 || realx >= Main.maxTilesX) - continue; - - for (int y = 0; y < size; y++) - { - int realy = tileY + y; - if (realy < 0 || realy >= Main.maxTilesY) - continue; - - var tile = Main.tile[realx, realy]; - var newtile = tiles[x, y]; - if (TShock.CheckTilePermission(args.Player, realx, realy)) - { - continue; - } - // Server now has a range check built in - /*if (TShock.CheckRangePermission(args.Player, realx, realy)) - { - continue; - }*/ - if ((tile.type == 128 && newtile.Type == 128) || (tile.type == 105 && newtile.Type == 105) || (tile.type == 139 && newtile.Type == 139)) - { - if (TShock.Config.EnableInsecureTileFixes) - { - return false; - } - } - - if (tile.type == 0x17 && newtile.Type == 0x2) - { - tile.type = 0x2; - changed = true; - } - else if (tile.type == 0x19 && newtile.Type == 0x1) - { - tile.type = 0x1; - changed = true; - } - else if ((tile.type == 0xF && newtile.Type == 0xF) || - (tile.type == 0x4F && newtile.Type == 0x4F)) - { - tile.frameX = newtile.FrameX; - tile.frameY = newtile.FrameY; - changed = true; - } - // Holy water/Unholy water - else if (tile.type == 1 && newtile.Type == 117) - { - tile.type = 117; - changed = true; - } - else if (tile.type == 1 && newtile.Type == 25) - { - tile.type = 25; - changed = true; - } - else if (tile.type == 117 && newtile.Type == 25) - { - tile.type = 25; - changed = true; - } - else if (tile.type == 25 && newtile.Type == 117) - { - tile.type = 117; - changed = true; - } - else if (tile.type == 2 && newtile.Type == 23) - { - tile.type = 23; - changed = true; - } - else if (tile.type == 2 && newtile.Type == 109) - { - tile.type = 109; - changed = true; - } - else if (tile.type == 23 && newtile.Type == 109) - { - tile.type = 109; - changed = true; - } - else if (tile.type == 109 && newtile.Type == 23) - { - tile.type = 23; - changed = true; - } - else if (tile.type == 23 && newtile.Type == 109) - { - tile.type = 109; - changed = true; - } - else if (tile.type == 53 && newtile.Type == 116) - { - tile.type = 116; - changed = true; - } - else if (tile.type == 53 && newtile.Type == 112) - { - tile.type = 112; - changed = true; - } - else if (tile.type == 112 && newtile.Type == 116) - { - tile.type = 116; - changed = true; - } - else if (tile.type == 116 && newtile.Type == 112) - { - tile.type = 112; - changed = true; - } - else if (tile.type == 112 && newtile.Type == 53) - { - tile.type = 53; - changed = true; - } - else if (tile.type == 109 && newtile.Type == 2) - { - tile.type = 2; - changed = true; - } - else if (tile.type == 116 && newtile.Type == 53) - { - tile.type = 53; - changed = true; - } - else if (tile.type == 117 && newtile.Type == 1) - { - tile.type = 1; - changed = true; - } - } - } - - if (changed) - { - TSPlayer.All.SendTileSquare(tileX, tileY, size); - WorldGen.RangeFrame(tileX, tileY, tileX + size, tileY + size); - } - else - { - args.Player.SendTileSquare(tileX, tileY, size); - } - return true; - } - - private static bool HandleTile(GetDataHandlerArgs args) - { - var type = args.Data.ReadInt8(); - var tileX = args.Data.ReadInt32(); - var tileY = args.Data.ReadInt32(); - var tiletype = args.Data.ReadInt8(); - if (OnTileEdit(args.Player, tileX, tileY, tiletype, type)) - return true; - if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) - return false; - - if (args.Player.AwaitingName) - { - var protectedregions = TShock.Regions.InAreaRegionName(tileX, tileY); - if (protectedregions.Count == 0) - { - args.Player.SendMessage("Region is not protected", Color.Yellow); - } - else - { - string regionlist = string.Join(",", protectedregions.ToArray()); - args.Player.SendMessage("Region Name(s): " + regionlist, Color.Yellow); - } - args.Player.SendTileSquare(tileX, tileY); - args.Player.AwaitingName = false; - return true; - } - - if (args.Player.AwaitingTempPoint > 0) - { - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; - args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].Y = tileY; - args.Player.SendMessage("Set Temp Point " + args.Player.AwaitingTempPoint, Color.Yellow); - args.Player.SendTileSquare(tileX, tileY); - args.Player.AwaitingTempPoint = 0; - return true; - } - - if (type == 1 || type == 3) - { - if (tiletype >= ((type == 1) ? Main.maxTileSets : Main.maxWallTypes)) - { - return true; - } - if (tiletype == 29 && tiletype == 97 && TShock.Config.ServerSideInventory) - { - args.Player.SendMessage("You cannot place this tile, Server side inventory is enabled.", Color.Red); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - if (tiletype == 48 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned("Spike", args.Player)) - { - args.Player.Disable("Using banned spikes without permissions"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - if (type == 1 && tiletype == 21 && TShock.Utils.MaxChests()) - { - args.Player.SendMessage("Reached world's max chest limit, unable to place more!", Color.Red); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - if (tiletype == 141 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned("Explosives", args.Player)) - { - args.Player.Disable("Using banned explosives tile without permissions"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY, tiletype, type)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if ((tiletype == 127 || Main.tileCut[tiletype]) && (type == 0 || type == 4)) - { - return false; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (args.Player.TileKillThreshold >= TShock.Config.TileKillThreshold) - { - args.Player.Disable("Reached TileKill threshold"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) - { - args.Player.Disable("Reached TilePlace threshold"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (type == 1 && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection)) - { - args.Player.TilePlaceThreshold++; - var coords = new Vector2(tileX, tileY); - if (!args.Player.TilesCreated.ContainsKey(coords)) - args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY].Data); - } - - if ((type == 0 || type == 4) && Main.tileSolid[Main.tile[tileX, tileY].type] && - !args.Player.Group.HasPermission(Permissions.ignorekilltiledetection)) - { - args.Player.TileKillThreshold++; - var coords = new Vector2(tileX, tileY); - if (!args.Player.TilesDestroyed.ContainsKey(coords)) - args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY].Data); - } - - return false; - } - - private static bool HandleTogglePvp(GetDataHandlerArgs args) - { - byte id = args.Data.ReadInt8(); - bool pvp = args.Data.ReadBoolean(); - if (OnPvpToggled(id, pvp)) - return true; - - if (id != args.Player.Index) - { - return true; - } - - if (TShock.Config.PvPMode == "disabled") - { - return true; - } - - if (args.TPlayer.hostile != pvp) - { - long seconds = (long) (DateTime.UtcNow - args.Player.LastPvpChange).TotalSeconds; - if (seconds > 5) - { - TSPlayer.All.SendMessage(string.Format("{0} has {1} PvP!", args.Player.Name, pvp ? "enabled" : "disabled"), - Main.teamColor[args.Player.Team]); - } - args.Player.LastPvpChange = DateTime.UtcNow; - } - - args.TPlayer.hostile = pvp; - - if (TShock.Config.PvPMode == "always") - { - if (!pvp) - args.Player.Spawn(); - } - - NetMessage.SendData((int) PacketTypes.TogglePvp, -1, -1, "", args.Player.Index); - - return true; - } - - private static bool HandlePlayerUpdate(GetDataHandlerArgs args) - { - var plr = args.Data.ReadInt8(); - var control = args.Data.ReadInt8(); - var item = args.Data.ReadInt8(); - var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - if (OnPlayerUpdate(plr, control, item, pos, vel)) - return true; - if (item < 0 || item >= args.TPlayer.inventory.Length) - { - return true; - } - - if (args.Player.LastNetPosition == Vector2.Zero) - { - return true; - } - - if (!pos.Equals(args.Player.LastNetPosition)) - { - float distance = Vector2.Distance(new Vector2(pos.X/16f, pos.Y/16f), - new Vector2(args.Player.LastNetPosition.X/16f, args.Player.LastNetPosition.Y/16f)); - if (TShock.CheckIgnores(args.Player)) - { - if (distance > TShock.Config.MaxRangeForDisabled) - { - if (args.Player.IgnoreActionsForCheating != "none") - { - args.Player.SendMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating, - Color.Red); - } - else if (args.Player.IgnoreActionsForDisabledArmor != "none") - { - args.Player.SendMessage( - "Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor, Color.Red); - } - else if (args.Player.IgnoreActionsForInventory != "none") - { - args.Player.SendMessage( - "Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory, - Color.Red); - } - else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn) - { - args.Player.SendMessage("Please /register or /login to play!", Color.Red); - } - else if (args.Player.IgnoreActionsForClearingTrashCan) - { - args.Player.SendMessage("You need to rejoin to ensure your trash can is cleared!", Color.Red); - } - else if (TShock.Config.PvPMode == "always" && !args.TPlayer.hostile) - { - args.Player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", - Color.Red); - } - int lastTileX = (int) (args.Player.LastNetPosition.X/16f); - int lastTileY = (int) (args.Player.LastNetPosition.Y/16f); - if (!args.Player.Teleport(lastTileX, lastTileY)) - { - args.Player.Spawn(); - } - return true; - } - return true; - } - - if (args.Player.Dead) - { - return true; - } - - if (!args.Player.Group.HasPermission(Permissions.ignorenoclipdetection) && - TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip) - { - int lastTileX = (int) (args.Player.LastNetPosition.X/16f); - int lastTileY = (int) (args.Player.LastNetPosition.Y/16f); - if (!args.Player.Teleport(lastTileX, lastTileY + 3)) - { - args.Player.SendMessage("You got stuck in a solid object, Sent to spawn point."); - args.Player.Spawn(); - } - return true; - } - args.Player.LastNetPosition = pos; - } - - if ((control & 32) == 32) - { - if (!args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned(args.TPlayer.inventory[item].name, args.Player)) - { - control -= 32; - args.Player.Disable("Using banned item"); - args.Player.SendMessage( - string.Format("You cannot use {0} on this server. Your actions are being ignored.", - args.TPlayer.inventory[item].name), Color.Red); - } - } - - args.TPlayer.selectedItem = item; - args.TPlayer.position = pos; - args.TPlayer.velocity = vel; - args.TPlayer.oldVelocity = args.TPlayer.velocity; - args.TPlayer.fallStart = (int) (pos.Y/16f); - args.TPlayer.controlUp = false; - args.TPlayer.controlDown = false; - args.TPlayer.controlLeft = false; - args.TPlayer.controlRight = false; - args.TPlayer.controlJump = false; - args.TPlayer.controlUseItem = false; - args.TPlayer.direction = -1; - if ((control & 1) == 1) - { - args.TPlayer.controlUp = true; - } - if ((control & 2) == 2) - { - args.TPlayer.controlDown = true; - } - if ((control & 4) == 4) - { - args.TPlayer.controlLeft = true; - } - if ((control & 8) == 8) - { - args.TPlayer.controlRight = true; - } - if ((control & 16) == 16) - { - args.TPlayer.controlJump = true; - } - if ((control & 32) == 32) - { - args.TPlayer.controlUseItem = true; - } - if ((control & 64) == 64) - { - args.TPlayer.direction = 1; - } - NetMessage.SendData((int) PacketTypes.PlayerUpdate, -1, args.Player.Index, "", args.Player.Index); - - return true; - } - - private static bool HandleProjectileNew(GetDataHandlerArgs args) - { - var ident = args.Data.ReadInt16(); - var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - var knockback = args.Data.ReadSingle(); - var dmg = args.Data.ReadInt16(); - var owner = args.Data.ReadInt8(); - var type = args.Data.ReadInt8(); - owner = (byte)args.Player.Index; - var index = TShock.Utils.SearchProjectile(ident, owner); - - if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index)) - return true; - - if (index > Main.maxProjectiles || index < 0) - { - return false; - } - - // Server now checks owner + ident, if owner is different, server will create new projectile. - /*if (args.Player.Index != owner) - { - args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to update projectile", owner, args.Player.Index)); - args.Player.RemoveProjectile(ident, owner); - return true; - }*/ - - if (dmg > TShock.Config.MaxProjDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) - { - args.Player.Disable(String.Format("Projectile damage is higher than {0}", TShock.Config.MaxProjDamage)); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (!TShock.Config.IgnoreProjUpdate && TShock.CheckProjectilePermission(args.Player, index, type)) - { - if (type == 100) - { //fix for skele prime - Log.Debug("Skeletron Prime's death laser ignored for cheat detection.."); - } - else - { - args.Player.Disable("Does not have projectile permission to update projectile."); - args.Player.RemoveProjectile(ident, owner); - } - return true; - } - - if (args.Player.ProjectileThreshold >= TShock.Config.ProjectileThreshold) - { - args.Player.Disable("Reached projectile update threshold"); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (!args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection)) - { - if ((type ==90) && (TShock.Config.ProjIgnoreShrapnel))// ignore shrapnel - { - Log.Debug("Ignoring shrapnel per config.."); - } - else - { - args.Player.ProjectileThreshold++; - } - } - - return false; - } - - private static bool HandleProjectileKill(GetDataHandlerArgs args) - { - var ident = args.Data.ReadInt16(); - var owner = args.Data.ReadInt8(); - owner = (byte)args.Player.Index; - var index = TShock.Utils.SearchProjectile(ident, owner); - - if (index > Main.maxProjectiles || index < 0) - { - return false; - } - - var type = Main.projectile[index].type; - - // Players can no longer destroy projectiles that are not theirs as of 1.1.2 - /*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles - { - args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type)); - args.Player.RemoveProjectile(ident, owner); - return true; - }*/ - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) - { - args.Player.Disable("Does not have projectile permission to kill projectile"); - args.Player.RemoveProjectile(ident, owner); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.RemoveProjectile(ident, owner); - return true; - } - - return false; - } - - private static bool HandlePlayerKillMe(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = args.Data.ReadInt8(); - var dmg = args.Data.ReadInt16(); - var pvp = args.Data.ReadInt8() == 0; - if (OnKillMe(id, direction, dmg, pvp)) - return true; - int textlength = (int) (args.Data.Length - args.Data.Position - 1); - string deathtext = ""; - if (textlength > 0) - { - deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength)); - /*if (!TShock.Utils.ValidString(deathtext)) - { - return true; - }*/ - } - - args.Player.LastDeath = DateTime.Now; - args.Player.Dead = true; - - return false; - } - - private static bool HandleLiquidSet(GetDataHandlerArgs args) - { - int tileX = args.Data.ReadInt32(); - int tileY = args.Data.ReadInt32(); - byte liquid = args.Data.ReadInt8(); - bool lava = args.Data.ReadBoolean(); - - if (OnLiquidSet(tileX, tileY, liquid, lava)) - return true; - - //The liquid was picked up. - if (liquid == 0) - return false; - - if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) - return false; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (args.Player.TileLiquidThreshold >= TShock.Config.TileLiquidThreshold) - { - args.Player.Disable("Reached TileLiquid threshold"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (!args.Player.Group.HasPermission(Permissions.ignoreliquidsetdetection)) - { - args.Player.TileLiquidThreshold++; - } - - int bucket = 0; - if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206) - { - bucket = 1; - } - else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 207) - { - bucket = 2; - } - - if (lava && bucket != 2 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)) - { - args.Player.Disable("Using banned lava bucket without permissions"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (!lava && bucket != 1 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)) - { - args.Player.Disable("Using banned water bucket without permissions"); - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY, 16)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - return false; - } - - private static bool HandleTileKill(GetDataHandlerArgs args) - { - var tileX = args.Data.ReadInt32(); - var tileY = args.Data.ReadInt32(); - if (OnTileKill(tileX, tileY)) - return true; - if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) - return false; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (Main.tile[tileX, tileY].type != 0x15 && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != 0)) //Chest - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (TShock.CheckTilePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - if (TShock.CheckRangePermission(args.Player, tileX, tileY)) - { - args.Player.SendTileSquare(tileX, tileY); - return true; - } - - return false; - } - - private static bool HandleSpawn(GetDataHandlerArgs args) - { - var player = args.Data.ReadInt8(); - var spawnx = args.Data.ReadInt32(); - var spawny = args.Data.ReadInt32(); - - if (OnPlayerSpawn(player, spawnx, spawny)) - return true; - - if (args.Player.InitSpawn && args.TPlayer.inventory[args.TPlayer.selectedItem].type != 50) - { - if (args.TPlayer.difficulty == 1 && (TShock.Config.KickOnMediumcoreDeath || TShock.Config.BanOnMediumcoreDeath)) - { - if (args.TPlayer.selectedItem != 50) - { - if (TShock.Config.BanOnMediumcoreDeath) - { - if (!TShock.Utils.Ban(args.Player, TShock.Config.MediumcoreBanReason)) - TShock.Utils.ForceKick(args.Player, "Death results in a ban, but can't ban you"); - } - else - { - TShock.Utils.ForceKick(args.Player, TShock.Config.MediumcoreKickReason); - } - return true; - } - } - } - else - args.Player.InitSpawn = true; - - args.Player.Dead = false; - return false; - } - - private static bool HandleChestOpen(GetDataHandlerArgs args) - { - var x = args.Data.ReadInt32(); - var y = args.Data.ReadInt32(); - - if (OnChestOpen(x, y)) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - return true; - } - - if (TShock.CheckRangePermission(args.Player, x, y)) - { - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y) && TShock.Config.RegionProtectChests) - { - return true; - } - - return false; - } - - private static bool HandleChestItem(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt16(); - var slot = args.Data.ReadInt8(); - var stacks = args.Data.ReadInt8(); - var prefix = args.Data.ReadInt8(); - var type = args.Data.ReadInt16(); - - if (OnChestItemChange(id, slot, stacks, prefix, type)) - return true; - - if (args.TPlayer.chest != id) - { - return false; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.ChestItem, "", id, slot); - return true; - } - - Item item = new Item(); - item.netDefaults(type); - if (stacks > item.maxStack || TShock.Itembans.ItemIsBanned(item.name, args.Player)) - { - return false; - } - - if (TShock.CheckTilePermission(args.Player, Main.chest[id].x, Main.chest[id].y) && TShock.Config.RegionProtectChests) - { - return false; - } - - if (TShock.CheckRangePermission(args.Player, Main.chest[id].x, Main.chest[id].y)) - { - return false; - } - - return false; - } - - private static bool HandleSign(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt16(); - var x = args.Data.ReadInt32(); - var y = args.Data.ReadInt32(); - - if (OnSignEvent(id, x, y)) - return true; - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - args.Player.SendData(PacketTypes.SignNew, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, x, y)) - { - args.Player.SendData(PacketTypes.SignNew, "", id); - return true; - } - return false; - } - - private static bool UpdateNPCHome(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt16(); - var x = args.Data.ReadInt16(); - var y = args.Data.ReadInt16(); - var homeless = args.Data.ReadInt8(); - - if (OnUpdateNPCHome(id, x, y, homeless)) - return true; - - if (!args.Player.Group.HasPermission(Permissions.movenpc)) - { - args.Player.SendMessage("You do not have permission to relocate NPCs.", Color.Red); - args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, - Convert.ToByte(Main.npc[id].homeless)); - return true; - } - - if (TShock.CheckTilePermission(args.Player, x, y)) - { - args.Player.SendMessage( "You do not have access to modify this area.", Color.Red); - args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, - Convert.ToByte(Main.npc[id].homeless)); - return true; - } - - //removed until NPC Home packet actually sends their home coords. - /*if (TShock.CheckRangePermission(args.Player, x, y)) - { - args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, - Convert.ToByte(Main.npc[id].homeless)); - return true; - }*/ - return false; - } - - private static bool HandlePlayerBuff(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var type = args.Data.ReadInt8(); - var time = args.Data.ReadInt16(); - - if (OnPlayerBuff(id, type, time)) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerBuff, "", id); - return true; - } - if (!TShock.Players[id].TPlayer.hostile) - { - args.Player.SendData(PacketTypes.PlayerBuff, "", id); - return true; - } - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 50)) - { - args.Player.SendData(PacketTypes.PlayerBuff, "", id); - return true; - } - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerBuff, "", id); - return true; - } - - if (WhitelistBuffMaxTime[type] > 0 && time <= WhitelistBuffMaxTime[type]) - { - return false; - } - - args.Player.SendData(PacketTypes.PlayerBuff, "", id); - return true; - } - - private static bool HandleItemDrop(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt16(); - var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); - var stacks = args.Data.ReadInt8(); - var prefix = args.Data.ReadInt8(); - var type = args.Data.ReadInt16(); - - if (OnItemDrop(id, pos, vel, stacks, prefix, type)) - return true; - - if (type == 0) //Item removed, let client do this to prevent item duplication client side - { - return false; - } - - if (TShock.CheckRangePermission(args.Player, (int) (pos.X/16f), (int) (pos.Y/16f))) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - Item item = new Item(); - item.netDefaults(type); - if (stacks > item.maxStack || TShock.Itembans.ItemIsBanned(item.name, args.Player)) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - if ((TShock.Config.ServerSideInventory) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.Config.LogonDiscardThreshold)) - { - //Player is probably trying to sneak items onto the server in their hands!!! - Log.ConsoleInfo(string.Format("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.name)); - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - - } - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.ItemDrop, "", id); - return true; - } - - return false; - } - - private static bool HandlePlayerDamage(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = args.Data.ReadInt8(); - var dmg = args.Data.ReadInt16(); - var pvp = args.Data.ReadInt8(); - var crit = args.Data.ReadInt8(); - - if (OnPlayerDamage(id, direction, dmg, pvp, crit)) - return true; - - int textlength = (int) (args.Data.Length - args.Data.Position - 1); - string deathtext = ""; - if (textlength > 0) - { - deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength)); - /*if (!TShock.Utils.ValidString(deathtext)) - { - return true; - }*/ - } - - if (TShock.Players[id] == null) - return true; - - if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) - { - args.Player.Disable(String.Format("Player damage exceeded {0}", TShock.Config.MaxDamage ) ); - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - return false; - } - - private static bool HandleNpcStrike(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = args.Data.ReadInt8(); - var dmg = args.Data.ReadInt16(); - var pvp = args.Data.ReadInt8(); - var crit = args.Data.ReadInt8(); - - if (OnNPCStrike(id, direction, dmg, pvp, crit)) - return true; - - if (Main.npc[id] == null) - return true; - - if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) - { - args.Player.Disable(String.Format("NPC damage exceeded {0}", TShock.Config.MaxDamage ) ); - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.movenpc)) - { - args.Player.SendMessage( "You don't have permission to move the NPC", Color.Yellow); - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if (TShock.Config.RangeChecks && - TShock.CheckRangePermission(args.Player, (int) (Main.npc[id].position.X/16f), (int) (Main.npc[id].position.Y/16f), - 128)) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.NpcUpdate, "", id); - return true; - } - - return false; - } - - private static bool HandleSpecial(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var type = args.Data.ReadInt8(); - - if (OnNPCSpecial(id, type)) - return true; - - if (type == 1 && TShock.Config.DisableDungeonGuardian) - { - args.Player.SendMessage("The Dungeon Guardian returned you to your spawn point", Color.Purple); - args.Player.Spawn(); - return true; - } - - return false; - } - - private static bool HandlePlayerAnimation(GetDataHandlerArgs args) - { - - if (OnPlayerAnimation()) - return true; - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); - return true; - } - - return false; - } - - private static bool HandlePlayerBuffUpdate(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - - if (OnPlayerBuffUpdate(id)) - return true; - - for (int i = 0; i < 10; i++) - { - var buff = args.Data.ReadInt8(); - - if (buff == 10) - { - if (!args.Player.Group.HasPermission(Permissions.usebanneditem) && - TShock.Itembans.ItemIsBanned("Invisibility Potion", args.Player)) - buff = 0; - else if (TShock.Config.DisableInvisPvP && args.TPlayer.hostile) - buff = 0; - } - - args.TPlayer.buffType[i] = buff; - if (args.TPlayer.buffType[i] > 0) - { - args.TPlayer.buffTime[i] = 60; - } - else - { - args.TPlayer.buffTime[i] = 0; - } - } - NetMessage.SendData((int) PacketTypes.PlayerBuff, -1, args.Player.Index, "", args.Player.Index); - return true; - } - - private static bool HandleSpawnBoss(GetDataHandlerArgs args) - { - var spawnboss = false; - var invasion = -1; - var plr = args.Data.ReadInt32(); - var Type = args.Data.ReadInt32(); - spawnboss = (Type == 4 || Type == 13 || (Type == 50 || Type == 125) || (Type == 126 || Type == 134 || (Type == (int) sbyte.MaxValue || Type == 128))); - if (!spawnboss) - { - switch (Type) - { - case -1: - invasion = 1; - break; - case -2: - invasion = 2; - break; - } - } - if (spawnboss && !args.Player.Group.HasPermission(Permissions.summonboss)) - { - args.Player.SendMessage("You don't have permission to summon a boss.", Color.Red); - return true; - } - if (invasion != -1 && !args.Player.Group.HasPermission(Permissions.startinvasion)) - { - args.Player.SendMessage("You don't have permission to start an invasion.", Color.Red); - return true; - } - if (!spawnboss && invasion == -1) - return true; - if (plr != args.Player.Index) - return true; - - string boss; - switch (Type) - { - case -2: - boss = "the Snow Legion"; - break; - case -1: - boss = "a Goblin Invasion"; - break; - case 4: - boss = "the Eye of Cthulhu"; - break; - case 13: - boss = "the Eater of Worlds"; - break; - case 50: - boss = "the King Slime"; - break; - case 125: - boss = "Retinazer"; - break; - case 126: - boss = "Spazmatism"; - break; - case 134: - boss = "the Destroyer"; - break; - case sbyte.MaxValue: - boss = "Skeleton Prime"; - break; - case 128: - boss = "Skeleton Prime"; - break; - default: - boss = "error"; - break; - } - - TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.Red); - return false; - } - } -} +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.IO.Streams; +using System.Linq; +using System.Text; +using Terraria; +using TShockAPI.Net; + +namespace TShockAPI +{ + public delegate bool GetDataHandlerDelegate(GetDataHandlerArgs args); + + public class GetDataHandlerArgs : EventArgs + { + public TSPlayer Player { get; private set; } + public MemoryStream Data { get; private set; } + + public Player TPlayer + { + get { return Player.TPlayer; } + } + + public GetDataHandlerArgs(TSPlayer player, MemoryStream data) + { + Player = player; + Data = data; + } + } + + public static class GetDataHandlers + { + private static Dictionary GetDataHandlerDelegates; + public static int[] WhitelistBuffMaxTime; + #region Events + + /// + /// Used when a TileEdit event is called. + /// + public class TileEditEventArgs : HandledEventArgs + { + /// + /// The TSPlayer who made the tile edit + /// + public TSPlayer Player { get; set; } + + /// + /// The tile coordinate on the X plane + /// + public int X { get; set; } + + /// + /// The tile coordinate on the Y plane + /// + public int Y { get; set; } + + /// + /// The Tile ID being edited. + /// + public byte Type { get; set; } + /// + /// The EditType. + /// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6) + /// + public byte EditType { get; set; } + } + + /// + /// TileEdit - called when a tile is placed or destroyed + /// + public static HandlerList TileEdit; + private static bool OnTileEdit(TSPlayer ply, int x, int y, byte type, byte editType) + { + if (TileEdit == null) + return false; + + var args = new TileEditEventArgs + { + Player = ply, + X = x, + Y = y, + Type = type, + EditType = editType + }; + TileEdit.Invoke(null, args); + return args.Handled; + } + /// + /// For use in a TogglePvp event + /// + public class TogglePvpEventArgs : HandledEventArgs + { + /// + /// The Terraria player ID of the player + /// + public byte PlayerId { get; set; } + /// + /// Enable/disable pvp? + /// + public bool Pvp { get; set; } + } + /// + /// TogglePvp - called when a player toggles pvp + /// + public static HandlerList TogglePvp; + private static bool OnPvpToggled(byte _id, bool _pvp) + { + if (TogglePvp == null) + return false; + + var args = new TogglePvpEventArgs + { + PlayerId = _id, + Pvp = _pvp, + }; + TogglePvp.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerSlot event + /// + public class PlayerSlotEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID + /// + public byte PlayerId { get; set; } + /// + /// The slot edited + /// + public byte Slot { get; set; } + /// + /// The stack edited + /// + public byte Stack { get; set; } + /// + /// The item prefix + /// + public byte Prefix { get; set; } + /// + /// Item type + /// + public short Type { get; set; } + } + /// + /// PlayerSlot - called at a PlayerSlot event + /// + public static HandlerList PlayerSlot; + private static bool OnPlayerSlot(byte _plr, byte _slot, byte _stack, byte _prefix, short _type) + { + if (PlayerSlot == null) + return false; + + var args = new PlayerSlotEventArgs + { + PlayerId = _plr, + Slot = _slot, + Stack = _stack, + Prefix = _prefix, + Type = _type + }; + PlayerSlot.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerHP event + /// + public class PlayerHPEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte PlayerId { get; set; } + /// + /// Current HP + /// + public short Current { get; set; } + /// + /// Maximum HP + /// + public short Max { get; set; } + } + /// + /// PlayerHP - called at a PlayerHP event + /// + public static HandlerList PlayerHP; + + private static bool OnPlayerHP(byte _plr, short _cur, short _max) + { + if (PlayerHP == null) + return false; + + var args = new PlayerHPEventArgs + { + PlayerId = _plr, + Current = _cur, + Max = _max, + }; + PlayerHP.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerMana event + /// + public class PlayerManaEventArgs : HandledEventArgs + { + public byte PlayerId { get; set; } + public short Current { get; set; } + public short Max { get; set; } + } + /// + /// PlayerMana - called at a PlayerMana event + /// + public static HandlerList PlayerMana; + + private static bool OnPlayerMana(byte _plr, short _cur, short _max) + { + if (PlayerMana == null) + return false; + + var args = new PlayerManaEventArgs + { + PlayerId = _plr, + Current = _cur, + Max = _max, + }; + PlayerMana.Invoke(null, args); + return args.Handled; + } + + public class PlayerInfoEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte PlayerId { get; set; } + /// + /// Hair color + /// + public byte Hair { get; set; } + /// + /// Gender (male = true) + /// + public bool Male { get; set; } + /// + /// Character difficulty + /// + public byte Difficulty { get; set; } + /// + /// Player/character name + /// + public string Name { get; set; } + } + /// + /// PlayerInfo - called at a PlayerInfo event + /// If this is cancelled, the server will ForceKick the player. If this should be changed in the future, let someone know. + /// + public static HandlerList PlayerInfo; + + private static bool OnPlayerInfo(byte _plrid, byte _hair, bool _male, byte _difficulty, string _name) + { + if (PlayerInfo == null) + return false; + + var args = new PlayerInfoEventArgs + { + PlayerId = _plrid, + Hair = _hair, + Male = _male, + Difficulty = _difficulty, + Name = _name, + }; + PlayerInfo.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a TileKill event + /// + public class TileKillEventArgs : HandledEventArgs + { + /// + /// The X coordinate that is being killed + /// + public int TileX { get; set; } + /// + /// The Y coordinate that is being killed + /// + public int TileY { get; set; } + } + /// + /// TileKill - When a tile is removed fromt he world + /// + public static HandlerList TileKill; + + private static bool OnTileKill(int tilex, int tiley) + { + if (TileKill == null) + return false; + + var args = new TileKillEventArgs + { + TileX = tilex, + TileY = tiley, + }; + TileKill.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a KillMe event + /// + public class KillMeEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte PlayerId { get; set; } + /// + /// The direction the damage is coming from (?) + /// + public byte Direction { get; set; } + /// + /// Amount of damage delt + /// + public short Damage { get; set; } + /// + /// Player's current pvp setting + /// + public bool Pvp { get; set; } + } + /// + /// KillMe - Terraria's crappy way of handling damage from players + /// + public static HandlerList KillMe; + + private static bool OnKillMe(byte plr, byte direction, short damage, bool pvp) + { + if (KillMe == null) + return false; + + var args = new KillMeEventArgs + { + PlayerId = plr, + Direction = direction, + Damage = damage, + Pvp = pvp, + }; + KillMe.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerUpdate event + /// + public class PlayerUpdateEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte PlayerId { get; set; } + /// + /// ??? + /// + public byte Control { get; set; } + /// + /// Current item? + /// + public byte Item { get; set; } + /// + /// Position of the player + /// + public Vector2 Position { get; set; } + /// + /// Velocity of the player + /// + public Vector2 Velocity { get; set; } + } + /// + /// PlayerUpdate - When the player sends it's updated information to the server + /// + public static HandlerList PlayerUpdate; + + private static bool OnPlayerUpdate(byte player, byte control, byte item, Vector2 position, Vector2 velocity) + { + if (PlayerUpdate == null) + return false; + + var args = new PlayerUpdateEventArgs + { + PlayerId = player, + Control = control, + Item = item, + Position = position, + Velocity = velocity, + }; + PlayerUpdate.Invoke(null, args); + return args.Handled; + } + public static bool TSCheckNoclip(Vector2 Position, int Width, int Height) + { + int num = (int)(Position.X / 16f) - 1; + int num2 = (int)((Position.X + (float)Width) / 16f) + 2; + int num3 = (int)(Position.Y / 16f) - 1; + int num4 = (int)((Position.Y + (float)Height) / 16f) + 2; + if (num < 0) + { + num = 0; + } + if (num2 > Main.maxTilesX) + { + num2 = Main.maxTilesX; + } + if (num3 < 0) + { + num3 = 0; + } + if (num4 > Main.maxTilesY) + { + num4 = Main.maxTilesY; + } + for (int i = num; i < num2; i++) + { + for (int j = num3; j < num4; j++) + { + if (Main.tile[i, j] != null && Main.tile[i, j].active && Main.tileSolid[(int)Main.tile[i, j].type] && !Main.tileSolidTop[(int)Main.tile[i, j].type] &&(((int)Main.tile[i,j].type !=53) && ((int)Main.tile[i,j].type !=112) && ((int)Main.tile[i,j].type !=116) && ((int)Main.tile[i,j].type !=123)) && ((Main.tile[i,j].liquid == 0 )&& !Main.tile[i,j].lava)) + { + Vector2 vector; + vector.X = (float)(i * 16); + vector.Y = (float)(j * 16); + if (Position.X + (float)Width > vector.X && Position.X < vector.X + 16f && Position.Y + (float)Height > vector.Y && Position.Y < vector.Y + 16f) + { + return true; + } + } + } + } + return false; + } + + /// + /// For use in a SendTileSquare event + /// + public class SendTileSquareEventArgs : HandledEventArgs + { + /// + /// Size of the area + /// + public short Size { get; set; } + /// + /// A corner of the section + /// + public int TileX { get; set; } + /// + /// A corner of the section + /// + public int TileY { get; set; } + } + /// + /// SendTileSquare - When the player sends a tile square + /// + public static HandlerList SendTileSquare; + + private static bool OnSendTileSquare(short size, int tilex, int tiley) + { + if (SendTileSquare == null) + return false; + + var args = new SendTileSquareEventArgs + { + Size = size, + TileX = tilex, + TileY = tiley, + }; + SendTileSquare.Invoke(null, args); + return args.Handled; + } + /// + /// For use in a NewProjectile event + /// + public class NewProjectileEventArgs : HandledEventArgs + { + /// + /// ??? + /// + public short Identity { get; set; } + /// + /// Location of the projectile + /// + public Vector2 Position { get; set; } + /// + /// Velocity of the projectile + /// + public Vector2 Velocity { get; set; } + /// + /// Knockback + /// + public float Knockback { get; set; } + /// + /// Damage from the projectile + /// + public short Damage { get; set; } + /// + /// Terraria playerID owner of the projectile + /// + public byte Owner { get; set; } + /// + /// Type of projectile + /// + public byte Type { get; set; } + /// + /// ??? + /// + public int Index { get; set; } + } + /// + /// NewProjectile - Called when a client creates a new projectile + /// + public static HandlerList NewProjectile; + + private static bool OnNewProjectile(short ident, Vector2 pos, Vector2 vel, float knockback, short dmg, byte owner, byte type, int index) + { + if (NewProjectile == null) + return false; + + var args = new NewProjectileEventArgs + { + Identity = ident, + Position = pos, + Velocity = vel, + Knockback = knockback, + Damage = dmg, + Owner = owner, + Type = type, + Index = index, + }; + NewProjectile.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a LiquidSet event + /// + public class LiquidSetEventArgs : HandledEventArgs + { + /// + /// X location of the tile + /// + public int TileX { get; set; } + /// + /// Y location of the tile + /// + public int TileY { get; set; } + /// + /// ??? + /// + public byte Liquid { get; set;} + /// + /// True if lava + /// + public bool Lava { get; set; } + } + /// + /// LiquidSet - When ever a liquid is set + /// + public static HandlerList LiquidSet; + + private static bool OnLiquidSet(int tilex, int tiley, byte liquid, bool lava) + { + if (LiquidSet == null) + return false; + + var args = new LiquidSetEventArgs + { + TileX = tilex, + TileY = tiley, + Liquid = liquid, + Lava = lava, + }; + LiquidSet.Invoke(null, args); + return args.Handled; + } + /// + /// For use in a PlayerSpawn event + /// + public class SpawnEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte Player { get; set; } + /// + /// X location of the player's spawn + /// + public int SpawnX { get; set; } + /// + /// Y location of the player's spawn + /// + public int SpawnY { get; set; } + } + /// + /// PlayerSpawn - When a player spawns + /// + public static HandlerList PlayerSpawn; + + private static bool OnPlayerSpawn(byte player, int spawnX, int spawnY) + { + if (PlayerSpawn == null) + return false; + + var args = new SpawnEventArgs + { + Player = player, + SpawnX = spawnX, + SpawnY = spawnY, + }; + PlayerSpawn.Invoke(null, args); + return args.Handled; + } + /// + /// For use with a ChestOpen event + /// + public class ChestOpenEventArgs : HandledEventArgs + { + /// + /// X location of said chest + /// + public int X { get; set; } + /// + /// Y location of said chest + /// + public int Y { get; set; } + } + /// + /// ChestOpen - Called when any chest is opened + /// + public static HandlerList ChestOpen; + + private static bool OnChestOpen(int x, int y) + { + if (ChestOpen == null) + return false; + + var args = new ChestOpenEventArgs + { + X = x, + Y = y, + }; + ChestOpen.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a ChestItemChange event + /// + public class ChestItemEventArgs : HandledEventArgs + { + /// + /// ChestID + /// + public short ID { get; set; } + /// + /// Slot of the item + /// + public byte Slot { get; set; } + /// + /// How many? + /// + public byte Stacks { get; set; } + /// + /// Item prefix + /// + public byte Prefix { get; set; } + /// + /// Item type + /// + public short Type { get; set; } + } + /// + /// ChestItemChange - Called when an item in a chest changes + /// + public static HandlerList ChestItemChange; + + private static bool OnChestItemChange(short id, byte slot, byte stacks, byte prefix, short type) + { + if (ChestItemChange == null) + return false; + + var args = new ChestItemEventArgs + { + ID = id, + Slot = slot, + Stacks = stacks, + Prefix = prefix, + Type = type, + }; + ChestItemChange.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a Sign event + /// + public class SignEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public short ID { get; set; } + /// + /// X location of the sign + /// + public int X { get; set; } + /// + /// Y location of the sign + /// + public int Y { get; set; } + } + /// + /// Sign - Called when a sign is changed + /// + public static HandlerList Sign; + + private static bool OnSignEvent(short id, int x, int y) + { + if (Sign == null) + return false; + + var args = new SignEventArgs + { + ID = id, + X = x, + Y = y, + }; + Sign.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a NPCHome event + /// + public class NPCHomeChangeEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public short ID { get; set; } + /// + /// X location of the NPC home change + /// + public short X { get; set; } + /// + /// Y location of the NPC home change + /// + public short Y { get; set; } + /// + /// ByteBool homeless + /// + public byte Homeless { get; set; } + } + /// + /// NPCHome - Called when an NPC's home is changed + /// + public static HandlerList NPCHome; + + private static bool OnUpdateNPCHome(short id, short x, short y, byte homeless) + { + if (NPCHome == null) + return false; + + var args = new NPCHomeChangeEventArgs + { + ID = id, + X = x, + Y = y, + Homeless = homeless, + }; + NPCHome.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerBuff event + /// + public class PlayerBuffEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte ID { get; set; } + /// + /// Buff Type + /// + public byte Type { get; set; } + /// + /// Time the buff lasts + /// + public short Time { get; set; } + } + /// + /// PlayerBuff - Called when a player is buffed + /// + public static HandlerList PlayerBuff; + + private static bool OnPlayerBuff(byte id, byte type, short time) + { + if (PlayerBuff == null) + return false; + + var args = new PlayerBuffEventArgs + { + ID = id, + Type = type, + Time = time, + }; + PlayerBuff.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in an ItemDrop event + /// + public class ItemDropEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public short ID { get; set; } + /// + /// Position of the item + /// + public Vector2 Position { get; set; } + /// + /// Velocity at which the item is deployed + /// + public Vector2 Velocity { get; set; } + /// + /// Stacks + /// + public byte Stacks { get; set; } + /// + /// Prefix of the item + /// + public byte Prefix { get; set; } + /// + /// Item type + /// + public short Type { get; set; } + } + /// + /// ItemDrop - Called when an item is dropped + /// + public static HandlerList ItemDrop; + + private static bool OnItemDrop(short id, Vector2 pos, Vector2 vel, byte stacks, byte prefix, short type) + { + if (ItemDrop == null) + return false; + + var args = new ItemDropEventArgs + { + ID = id, + Position = pos, + Velocity = vel, + Stacks = stacks, + Prefix = prefix, + Type = type, + }; + ItemDrop.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerDamage event + /// + public class PlayerDamageEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte ID { get; set; } + /// + /// The direction the damage is occuring from + /// + public byte Direction { get; set; } + /// + /// Amount of damage + /// + public short Damage { get; set; } + /// + /// If the player has PVP on + /// + public byte PVP { get; set; } + /// + /// Is the damage critical? + /// + public byte Critical { get; set; } + } + /// + /// PlayerDamage - Called when a player is damaged + /// + public static HandlerList PlayerDamage; + + private static bool OnPlayerDamage(byte id, byte dir, short dmg, byte pvp, byte crit) + { + if (PlayerDamage == null) + return false; + + var args = new PlayerDamageEventArgs + { + ID = id, + Direction = dir, + Damage = dmg, + PVP = pvp, + Critical = crit, + }; + PlayerDamage.Invoke(null, args); + return args.Handled; + } + + /// + /// For use with a NPCStrike event + /// + public class NPCStrikeEventArgs : HandledEventArgs + { + /// + /// ??? + /// + public byte ID { get; set; } + /// + /// Direction the damage occurred from + /// + public byte Direction { get; set; } + /// + /// Amount of damage + /// + public short Damage { get; set; } + /// + /// Is PVP enabled...? + /// + public byte PVP { get; set; } + /// + /// Critical? + /// + public byte Critical { get; set; } + } + /// + /// NPCStrike - Called when an NPC is attacked + /// + public static HandlerList NPCStrike; + + private static bool OnNPCStrike(byte id, byte dir, short dmg, byte pvp, byte crit) + { + if (NPCStrike == null) + return false; + + var args = new NPCStrikeEventArgs + { + ID = id, + Direction = dir, + Damage = dmg, + PVP = pvp, + Critical = crit, + }; + NPCStrike.Invoke(null, args); + return args.Handled; + } + + /// + /// For use with a NPCSpecial event + /// + public class NPCSpecialEventArgs : HandledEventArgs + { + /// + /// ??? + /// + public byte ID { get; set; } + /// + /// Type...? + /// + public byte Type { get; set; } + } + /// + /// NPCSpecial - Called at some point + /// + public static HandlerList NPCSpecial; + + private static bool OnNPCSpecial(byte id, byte type) + { + if (NPCSpecial == null) + return false; + + var args = new NPCSpecialEventArgs + { + ID = id, + Type = type, + }; + NPCSpecial.Invoke(null, args); + return args.Handled; + } + + /// + /// For use with a PlayerAnimation event + /// + public class PlayerAnimationEventArgs : HandledEventArgs + { + } + + /// + /// PlayerAnimation - Called when a player animates + /// + public static HandlerList PlayerAnimation; + + private static bool OnPlayerAnimation() + { + if (PlayerAnimation == null) + return false; + + var args = new PlayerAnimationEventArgs {}; + PlayerAnimation.Invoke(null, args); + return args.Handled; + } + + /// + /// For use in a PlayerBuffUpdate event + /// + public class PlayerBuffUpdateEventArgs : HandledEventArgs + { + /// + /// The Terraria playerID of the player + /// + public byte ID { get; set; } + } + /// + /// PlayerBuffUpdate - Called when a player updates buffs + /// + public static HandlerList PlayerBuffUpdate; + + private static bool OnPlayerBuffUpdate(byte id) + { + if (PlayerBuffUpdate == null) + return false; + + var args = new PlayerBuffUpdateEventArgs + { + ID = id, + }; + PlayerBuffUpdate.Invoke(null, args); + return args.Handled; + } + + #endregion + public static void InitGetDataHandler() + { + #region Blacklists + + WhitelistBuffMaxTime = new int[Main.maxBuffs]; + WhitelistBuffMaxTime[20] = 600; + WhitelistBuffMaxTime[0x18] = 1200; + WhitelistBuffMaxTime[0x1f] = 120; + WhitelistBuffMaxTime[0x27] = 420; + + #endregion Blacklists + + GetDataHandlerDelegates = new Dictionary + { + {PacketTypes.PlayerInfo, HandlePlayerInfo}, + {PacketTypes.PlayerUpdate, HandlePlayerUpdate}, + {PacketTypes.Tile, HandleTile}, + {PacketTypes.TileSendSquare, HandleSendTileSquare}, + {PacketTypes.ProjectileNew, HandleProjectileNew}, + {PacketTypes.TogglePvp, HandleTogglePvp}, + {PacketTypes.TileKill, HandleTileKill}, + {PacketTypes.PlayerKillMe, HandlePlayerKillMe}, + {PacketTypes.LiquidSet, HandleLiquidSet}, + {PacketTypes.PlayerSpawn, HandleSpawn}, + {PacketTypes.ChestGetContents, HandleChestOpen}, + {PacketTypes.ChestItem, HandleChestItem}, + {PacketTypes.SignNew, HandleSign}, + {PacketTypes.PlayerSlot, HandlePlayerSlot}, + {PacketTypes.TileGetSection, HandleGetSection}, + {PacketTypes.UpdateNPCHome, UpdateNPCHome}, + {PacketTypes.PlayerAddBuff, HandlePlayerBuff}, + {PacketTypes.ItemDrop, HandleItemDrop}, + {PacketTypes.PlayerHp, HandlePlayerHp}, + {PacketTypes.PlayerMana, HandlePlayerMana}, + {PacketTypes.PlayerDamage, HandlePlayerDamage}, + {PacketTypes.NpcStrike, HandleNpcStrike}, + {PacketTypes.NpcSpecial, HandleSpecial}, + {PacketTypes.PlayerAnimation, HandlePlayerAnimation}, + {PacketTypes.PlayerBuff, HandlePlayerBuffUpdate}, + {PacketTypes.PasswordSend, HandlePassword}, + {PacketTypes.ContinueConnecting2, HandleConnecting}, + {PacketTypes.ProjectileDestroy, HandleProjectileKill}, + {PacketTypes.SpawnBossorInvasion, HandleSpawnBoss} + }; + } + + public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data) + { + GetDataHandlerDelegate handler; + if (GetDataHandlerDelegates.TryGetValue(type, out handler)) + { + try + { + return handler(new GetDataHandlerArgs(player, data)); + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + } + return false; + } + + private static bool HandlePlayerSlot(GetDataHandlerArgs args) + { + byte plr = args.Data.ReadInt8(); + byte slot = args.Data.ReadInt8(); + byte stack = args.Data.ReadInt8(); + byte prefix = args.Data.ReadInt8(); + short type = args.Data.ReadInt16(); + + if (OnPlayerSlot(plr, slot, stack, prefix, type)) + return true; + + if (plr != args.Player.Index) + { + return true; + } + + if (slot < 0 || slot > NetItem.maxNetInventory) + { + return true; + } + + var item = new Item(); + item.netDefaults(type); + item.Prefix(prefix); + + if (args.Player.IsLoggedIn) + { + args.Player.PlayerData.StoreSlot(slot, type, prefix, stack); + } + + return false; + } + + public static bool HandlePlayerHp(GetDataHandlerArgs args) + { + var plr = args.Data.ReadInt8(); + var cur = args.Data.ReadInt16(); + var max = args.Data.ReadInt16(); + + if (OnPlayerHP(plr, cur, max)) + return true; + + if (args.Player.FirstMaxHP == 0) + args.Player.FirstMaxHP = max; + + if (max > 400 && max > args.Player.FirstMaxHP) + { + TShock.Utils.ForceKick(args.Player, "Hacked Client Detected."); + return false; + } + + if (args.Player.IsLoggedIn) + { + args.Player.PlayerData.maxHealth = max; + } + + return false; + } + + private static bool HandlePlayerMana(GetDataHandlerArgs args) + { + var plr = args.Data.ReadInt8(); + var cur = args.Data.ReadInt16(); + var max = args.Data.ReadInt16(); + + if (OnPlayerMana(plr, cur, max)) + return true; + + if (args.Player.FirstMaxMP == 0) + args.Player.FirstMaxMP = max; + + if (max > 400 && max > args.Player.FirstMaxMP) + { + TShock.Utils.ForceKick(args.Player, "Hacked Client Detected."); + return false; + } + + return false; + } + + private static bool HandlePlayerInfo(GetDataHandlerArgs args) + { + var playerid = args.Data.ReadInt8(); + var hair = args.Data.ReadInt8(); + var male = args.Data.ReadBoolean(); + args.Data.Position += 21; + var difficulty = args.Data.ReadInt8(); + string name = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1))); + + if (OnPlayerInfo(playerid, hair, male, difficulty, name)) + { + TShock.Utils.ForceKick(args.Player, "A plugin cancelled the event."); + return true; + } + + /*if (!TShock.Utils.ValidString(name)) + { + TShock.Utils.ForceKick(args.Player, "Unprintable character in name"); + return true; + }*/ + if (name.Trim().Length == 0) + { + TShock.Utils.ForceKick(args.Player, "Empty Name."); + return true; + } + var ban = TShock.Bans.GetBanByName(name); + if (ban != null) + { + TShock.Utils.ForceKick(args.Player, string.Format("You are banned: {0}", ban.Reason)); + return true; + } + if (args.Player.ReceivedInfo) + { + return true; + } + if (TShock.Config.MediumcoreOnly && difficulty < 1) + { + TShock.Utils.ForceKick(args.Player, "Server is set to mediumcore and above characters only!"); + return true; + } + if (TShock.Config.HardcoreOnly && difficulty < 2) + { + TShock.Utils.ForceKick(args.Player, "Server is set to hardcore characters only!"); + return true; + } + args.Player.Difficulty = difficulty; + args.TPlayer.name = name; + args.Player.ReceivedInfo = true; + + return false; + } + + private static bool HandleConnecting(GetDataHandlerArgs args) + { + var user = TShock.Users.GetUserByName(args.Player.Name); + if (user != null && !TShock.Config.DisableLoginBeforeJoin) + { + args.Player.RequiresPassword = true; + NetMessage.SendData((int) PacketTypes.PasswordRequired, args.Player.Index); + return true; + } + else if (!string.IsNullOrEmpty(TShock.Config.ServerPassword)) + { + args.Player.RequiresPassword = true; + NetMessage.SendData((int) PacketTypes.PasswordRequired, args.Player.Index); + return true; + } + + if (args.Player.State == 1) + args.Player.State = 2; + NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); + return true; + } + + private static bool HandlePassword(GetDataHandlerArgs args) + { + if (!args.Player.RequiresPassword) + return true; + + string password = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1))); + var user = TShock.Users.GetUserByName(args.Player.Name); + if (user != null) + { + string encrPass = TShock.Utils.HashPassword(password); + if (user.Password.ToUpper() == encrPass.ToUpper()) + { + args.Player.RequiresPassword = false; + args.Player.PlayerData = TShock.InventoryDB.GetPlayerData(args.Player, TShock.Users.GetUserID(args.Player.Name)); + + if (args.Player.State == 1) + args.Player.State = 2; + NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); + + var group = TShock.Utils.GetGroup(user.Group); + + if (TShock.Config.ServerSideInventory) + { + if (group.HasPermission(Permissions.bypassinventorychecks)) + { + args.Player.IgnoreActionsForClearingTrashCan = false; + } + else if (!TShock.CheckInventory(args.Player)) + { + args.Player.SendMessage("Login Failed, Please fix the above errors then /login again.", Color.Cyan); + args.Player.IgnoreActionsForClearingTrashCan = true; + return true; + } + } + + if (group.HasPermission(Permissions.ignorestackhackdetection)) + args.Player.IgnoreActionsForCheating = "none"; + + if (group.HasPermission(Permissions.usebanneditem)) + args.Player.IgnoreActionsForDisabledArmor = "none"; + + args.Player.Group = group; + args.Player.UserAccountName = args.Player.Name; + args.Player.UserID = TShock.Users.GetUserID(args.Player.UserAccountName); + args.Player.IsLoggedIn = true; + args.Player.IgnoreActionsForInventory = "none"; + + if (!args.Player.IgnoreActionsForClearingTrashCan) + { + args.Player.PlayerData.CopyInventory(args.Player); + TShock.InventoryDB.InsertPlayerData(args.Player); + } + args.Player.SendMessage("Authenticated as " + args.Player.Name + " successfully.", Color.LimeGreen); + Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + args.Player.Name); + return true; + } + TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true); + return true; + } + if (!string.IsNullOrEmpty(TShock.Config.ServerPassword)) + { + if (TShock.Config.ServerPassword == password) + { + args.Player.RequiresPassword = false; + if (args.Player.State == 1) + args.Player.State = 2; + NetMessage.SendData((int) PacketTypes.WorldInfo, args.Player.Index); + return true; + } + TShock.Utils.ForceKick(args.Player, "Incorrect Server Password"); + return true; + } + + TShock.Utils.ForceKick(args.Player, "Bad Password Attempt"); + return true; + } + + private static bool HandleGetSection(GetDataHandlerArgs args) + { + if (args.Player.RequestedSection) + return true; + + args.Player.RequestedSection = true; + if (TShock.HackedHealth(args.Player) && !args.Player.Group.HasPermission(Permissions.ignorestathackdetection)) + { + TShock.Utils.ForceKick(args.Player, "You have Hacked Health/Mana, Please use a different character."); + } + + if (!args.Player.Group.HasPermission(Permissions.ignorestackhackdetection)) + { + TShock.HackedInventory(args.Player); + } + + if (TShock.Utils.ActivePlayers() + 1 > TShock.Config.MaxSlots && + !args.Player.Group.HasPermission(Permissions.reservedslot)) + { + args.Player.SilentKickInProgress = true; + TShock.Utils.ForceKick(args.Player, TShock.Config.ServerFullReason); + return true; + } + + NetMessage.SendData((int) PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); + + if (TShock.Config.EnableGeoIP && TShock.Geo != null) + { + Log.Info(string.Format("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", args.Player.Name, args.Player.IP, + args.Player.Group.Name, args.Player.Country, TShock.Utils.ActivePlayers(), + TShock.Config.MaxSlots)); + TShock.Utils.Broadcast(args.Player.Name + " has joined from the " + args.Player.Country, Color.Yellow); + } + else + { + Log.Info(string.Format("{0} ({1}) from '{2}' group joined. ({3}/{4})", args.Player.Name, args.Player.IP, + args.Player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots)); + TShock.Utils.Broadcast(args.Player.Name + " has joined", Color.Yellow); + } + + if (TShock.Config.DisplayIPToAdmins) + TShock.Utils.SendLogs(string.Format("{0} has joined. IP: {1}", args.Player.Name, args.Player.IP), Color.Blue); + + return false; + } + + private static bool HandleSendTileSquare(GetDataHandlerArgs args) + { + if (args.Player.Group.HasPermission(Permissions.allowclientsideworldedit)) + return false; + + var size = args.Data.ReadInt16(); + var tileX = args.Data.ReadInt32(); + var tileY = args.Data.ReadInt32(); + + if (OnSendTileSquare(size, tileX, tileY)) + return true; + + if (size > 5) + return true; + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY, size); + return true; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + var tiles = new NetTile[size,size]; + + for (int x = 0; x < size; x++) + { + for (int y = 0; y < size; y++) + { + tiles[x, y] = new NetTile(args.Data); + } + } + + bool changed = false; + for (int x = 0; x < size; x++) + { + int realx = tileX + x; + if (realx < 0 || realx >= Main.maxTilesX) + continue; + + for (int y = 0; y < size; y++) + { + int realy = tileY + y; + if (realy < 0 || realy >= Main.maxTilesY) + continue; + + var tile = Main.tile[realx, realy]; + var newtile = tiles[x, y]; + if (TShock.CheckTilePermission(args.Player, realx, realy)) + { + continue; + } + // Server now has a range check built in + /*if (TShock.CheckRangePermission(args.Player, realx, realy)) + { + continue; + }*/ + if ((tile.type == 128 && newtile.Type == 128) || (tile.type == 105 && newtile.Type == 105) || (tile.type == 139 && newtile.Type == 139)) + { + if (TShock.Config.EnableInsecureTileFixes) + { + return false; + } + } + + if (tile.type == 0x17 && newtile.Type == 0x2) + { + tile.type = 0x2; + changed = true; + } + else if (tile.type == 0x19 && newtile.Type == 0x1) + { + tile.type = 0x1; + changed = true; + } + else if ((tile.type == 0xF && newtile.Type == 0xF) || + (tile.type == 0x4F && newtile.Type == 0x4F)) + { + tile.frameX = newtile.FrameX; + tile.frameY = newtile.FrameY; + changed = true; + } + // Holy water/Unholy water + else if (tile.type == 1 && newtile.Type == 117) + { + tile.type = 117; + changed = true; + } + else if (tile.type == 1 && newtile.Type == 25) + { + tile.type = 25; + changed = true; + } + else if (tile.type == 117 && newtile.Type == 25) + { + tile.type = 25; + changed = true; + } + else if (tile.type == 25 && newtile.Type == 117) + { + tile.type = 117; + changed = true; + } + else if (tile.type == 2 && newtile.Type == 23) + { + tile.type = 23; + changed = true; + } + else if (tile.type == 2 && newtile.Type == 109) + { + tile.type = 109; + changed = true; + } + else if (tile.type == 23 && newtile.Type == 109) + { + tile.type = 109; + changed = true; + } + else if (tile.type == 109 && newtile.Type == 23) + { + tile.type = 23; + changed = true; + } + else if (tile.type == 23 && newtile.Type == 109) + { + tile.type = 109; + changed = true; + } + else if (tile.type == 53 && newtile.Type == 116) + { + tile.type = 116; + changed = true; + } + else if (tile.type == 53 && newtile.Type == 112) + { + tile.type = 112; + changed = true; + } + else if (tile.type == 112 && newtile.Type == 116) + { + tile.type = 116; + changed = true; + } + else if (tile.type == 116 && newtile.Type == 112) + { + tile.type = 112; + changed = true; + } + else if (tile.type == 112 && newtile.Type == 53) + { + tile.type = 53; + changed = true; + } + else if (tile.type == 109 && newtile.Type == 2) + { + tile.type = 2; + changed = true; + } + else if (tile.type == 116 && newtile.Type == 53) + { + tile.type = 53; + changed = true; + } + else if (tile.type == 117 && newtile.Type == 1) + { + tile.type = 1; + changed = true; + } + } + } + + if (changed) + { + TSPlayer.All.SendTileSquare(tileX, tileY, size); + WorldGen.RangeFrame(tileX, tileY, tileX + size, tileY + size); + } + else + { + args.Player.SendTileSquare(tileX, tileY, size); + } + return true; + } + + private static bool HandleTile(GetDataHandlerArgs args) + { + var type = args.Data.ReadInt8(); + var tileX = args.Data.ReadInt32(); + var tileY = args.Data.ReadInt32(); + var tiletype = args.Data.ReadInt8(); + if (OnTileEdit(args.Player, tileX, tileY, tiletype, type)) + return true; + if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) + return false; + + if (args.Player.AwaitingName) + { + var protectedregions = TShock.Regions.InAreaRegionName(tileX, tileY); + if (protectedregions.Count == 0) + { + args.Player.SendMessage("Region is not protected", Color.Yellow); + } + else + { + string regionlist = string.Join(",", protectedregions.ToArray()); + args.Player.SendMessage("Region Name(s): " + regionlist, Color.Yellow); + } + args.Player.SendTileSquare(tileX, tileY); + args.Player.AwaitingName = false; + return true; + } + + if (args.Player.AwaitingTempPoint > 0) + { + args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].X = tileX; + args.Player.TempPoints[args.Player.AwaitingTempPoint - 1].Y = tileY; + args.Player.SendMessage("Set Temp Point " + args.Player.AwaitingTempPoint, Color.Yellow); + args.Player.SendTileSquare(tileX, tileY); + args.Player.AwaitingTempPoint = 0; + return true; + } + + if (type == 1 || type == 3) + { + if (tiletype >= ((type == 1) ? Main.maxTileSets : Main.maxWallTypes)) + { + return true; + } + if (tiletype == 29 && tiletype == 97 && TShock.Config.ServerSideInventory) + { + args.Player.SendMessage("You cannot place this tile, Server side inventory is enabled.", Color.Red); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + if (tiletype == 48 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned("Spike", args.Player)) + { + args.Player.Disable("Using banned spikes without permissions"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + if (type == 1 && tiletype == 21 && TShock.Utils.MaxChests()) + { + args.Player.SendMessage("Reached world's max chest limit, unable to place more!", Color.Red); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + if (tiletype == 141 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned("Explosives", args.Player)) + { + args.Player.Disable("Using banned explosives tile without permissions"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY, tiletype, type)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if ((tiletype == 127 || Main.tileCut[tiletype]) && (type == 0 || type == 4)) + { + return false; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (args.Player.TileKillThreshold >= TShock.Config.TileKillThreshold) + { + args.Player.Disable("Reached TileKill threshold"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (args.Player.TilePlaceThreshold >= TShock.Config.TilePlaceThreshold) + { + args.Player.Disable("Reached TilePlace threshold"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (type == 1 && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection)) + { + args.Player.TilePlaceThreshold++; + var coords = new Vector2(tileX, tileY); + if (!args.Player.TilesCreated.ContainsKey(coords)) + args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY].Data); + } + + if ((type == 0 || type == 4) && Main.tileSolid[Main.tile[tileX, tileY].type] && + !args.Player.Group.HasPermission(Permissions.ignorekilltiledetection)) + { + args.Player.TileKillThreshold++; + var coords = new Vector2(tileX, tileY); + if (!args.Player.TilesDestroyed.ContainsKey(coords)) + args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY].Data); + } + + return false; + } + + private static bool HandleTogglePvp(GetDataHandlerArgs args) + { + byte id = args.Data.ReadInt8(); + bool pvp = args.Data.ReadBoolean(); + if (OnPvpToggled(id, pvp)) + return true; + + if (id != args.Player.Index) + { + return true; + } + + if (TShock.Config.PvPMode == "disabled") + { + return true; + } + + if (args.TPlayer.hostile != pvp) + { + long seconds = (long) (DateTime.UtcNow - args.Player.LastPvpChange).TotalSeconds; + if (seconds > 5) + { + TSPlayer.All.SendMessage(string.Format("{0} has {1} PvP!", args.Player.Name, pvp ? "enabled" : "disabled"), + Main.teamColor[args.Player.Team]); + } + args.Player.LastPvpChange = DateTime.UtcNow; + } + + args.TPlayer.hostile = pvp; + + if (TShock.Config.PvPMode == "always") + { + if (!pvp) + args.Player.Spawn(); + } + + NetMessage.SendData((int) PacketTypes.TogglePvp, -1, -1, "", args.Player.Index); + + return true; + } + + private static bool HandlePlayerUpdate(GetDataHandlerArgs args) + { + var plr = args.Data.ReadInt8(); + var control = args.Data.ReadInt8(); + var item = args.Data.ReadInt8(); + var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + if (OnPlayerUpdate(plr, control, item, pos, vel)) + return true; + if (item < 0 || item >= args.TPlayer.inventory.Length) + { + return true; + } + + if (args.Player.LastNetPosition == Vector2.Zero) + { + return true; + } + + if (!pos.Equals(args.Player.LastNetPosition)) + { + float distance = Vector2.Distance(new Vector2(pos.X/16f, pos.Y/16f), + new Vector2(args.Player.LastNetPosition.X/16f, args.Player.LastNetPosition.Y/16f)); + if (TShock.CheckIgnores(args.Player)) + { + if (distance > TShock.Config.MaxRangeForDisabled) + { + if (args.Player.IgnoreActionsForCheating != "none") + { + args.Player.SendMessage("Disabled for cheating: " + args.Player.IgnoreActionsForCheating, + Color.Red); + } + else if (args.Player.IgnoreActionsForDisabledArmor != "none") + { + args.Player.SendMessage( + "Disabled for banned armor: " + args.Player.IgnoreActionsForDisabledArmor, Color.Red); + } + else if (args.Player.IgnoreActionsForInventory != "none") + { + args.Player.SendMessage( + "Disabled for Server Side Inventory: " + args.Player.IgnoreActionsForInventory, + Color.Red); + } + else if (TShock.Config.RequireLogin && !args.Player.IsLoggedIn) + { + args.Player.SendMessage("Please /register or /login to play!", Color.Red); + } + else if (args.Player.IgnoreActionsForClearingTrashCan) + { + args.Player.SendMessage("You need to rejoin to ensure your trash can is cleared!", Color.Red); + } + else if (TShock.Config.PvPMode == "always" && !args.TPlayer.hostile) + { + args.Player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", + Color.Red); + } + int lastTileX = (int) (args.Player.LastNetPosition.X/16f); + int lastTileY = (int) (args.Player.LastNetPosition.Y/16f); + if (!args.Player.Teleport(lastTileX, lastTileY)) + { + args.Player.Spawn(); + } + return true; + } + return true; + } + + if (args.Player.Dead) + { + return true; + } + + if (!args.Player.Group.HasPermission(Permissions.ignorenoclipdetection) && + TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip) + { + int lastTileX = (int) (args.Player.LastNetPosition.X/16f); + int lastTileY = (int) (args.Player.LastNetPosition.Y/16f); + if (!args.Player.Teleport(lastTileX, lastTileY + 3)) + { + args.Player.SendMessage("You got stuck in a solid object, Sent to spawn point."); + args.Player.Spawn(); + } + return true; + } + args.Player.LastNetPosition = pos; + } + + if ((control & 32) == 32) + { + if (!args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned(args.TPlayer.inventory[item].name, args.Player)) + { + control -= 32; + args.Player.Disable("Using banned item"); + args.Player.SendMessage( + string.Format("You cannot use {0} on this server. Your actions are being ignored.", + args.TPlayer.inventory[item].name), Color.Red); + } + } + + args.TPlayer.selectedItem = item; + args.TPlayer.position = pos; + args.TPlayer.velocity = vel; + args.TPlayer.oldVelocity = args.TPlayer.velocity; + args.TPlayer.fallStart = (int) (pos.Y/16f); + args.TPlayer.controlUp = false; + args.TPlayer.controlDown = false; + args.TPlayer.controlLeft = false; + args.TPlayer.controlRight = false; + args.TPlayer.controlJump = false; + args.TPlayer.controlUseItem = false; + args.TPlayer.direction = -1; + if ((control & 1) == 1) + { + args.TPlayer.controlUp = true; + } + if ((control & 2) == 2) + { + args.TPlayer.controlDown = true; + } + if ((control & 4) == 4) + { + args.TPlayer.controlLeft = true; + } + if ((control & 8) == 8) + { + args.TPlayer.controlRight = true; + } + if ((control & 16) == 16) + { + args.TPlayer.controlJump = true; + } + if ((control & 32) == 32) + { + args.TPlayer.controlUseItem = true; + } + if ((control & 64) == 64) + { + args.TPlayer.direction = 1; + } + NetMessage.SendData((int) PacketTypes.PlayerUpdate, -1, args.Player.Index, "", args.Player.Index); + + return true; + } + + private static bool HandleProjectileNew(GetDataHandlerArgs args) + { + var ident = args.Data.ReadInt16(); + var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + var knockback = args.Data.ReadSingle(); + var dmg = args.Data.ReadInt16(); + var owner = args.Data.ReadInt8(); + var type = args.Data.ReadInt8(); + owner = (byte)args.Player.Index; + var index = TShock.Utils.SearchProjectile(ident, owner); + + if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index)) + return true; + + if (index > Main.maxProjectiles || index < 0) + { + return false; + } + + // Server now checks owner + ident, if owner is different, server will create new projectile. + /*if (args.Player.Index != owner) + { + args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to update projectile", owner, args.Player.Index)); + args.Player.RemoveProjectile(ident, owner); + return true; + }*/ + + if (dmg > TShock.Config.MaxProjDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) + { + args.Player.Disable(String.Format("Projectile damage is higher than {0}", TShock.Config.MaxProjDamage)); + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if (!TShock.Config.IgnoreProjUpdate && TShock.CheckProjectilePermission(args.Player, index, type)) + { + if (type == 100) + { //fix for skele prime + Log.Debug("Skeletron Prime's death laser ignored for cheat detection.."); + } + else + { + args.Player.Disable("Does not have projectile permission to update projectile."); + args.Player.RemoveProjectile(ident, owner); + } + return true; + } + + if (args.Player.ProjectileThreshold >= TShock.Config.ProjectileThreshold) + { + args.Player.Disable("Reached projectile update threshold"); + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if (!args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection)) + { + if ((type ==90) && (TShock.Config.ProjIgnoreShrapnel))// ignore shrapnel + { + Log.Debug("Ignoring shrapnel per config.."); + } + else + { + args.Player.ProjectileThreshold++; + } + } + + return false; + } + + private static bool HandleProjectileKill(GetDataHandlerArgs args) + { + var ident = args.Data.ReadInt16(); + var owner = args.Data.ReadInt8(); + owner = (byte)args.Player.Index; + var index = TShock.Utils.SearchProjectile(ident, owner); + + if (index > Main.maxProjectiles || index < 0) + { + return false; + } + + var type = Main.projectile[index].type; + + // Players can no longer destroy projectiles that are not theirs as of 1.1.2 + /*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles + { + args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type)); + args.Player.RemoveProjectile(ident, owner); + return true; + }*/ + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if (TShock.CheckProjectilePermission(args.Player, index, type) && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) + { + args.Player.Disable("Does not have projectile permission to kill projectile"); + args.Player.RemoveProjectile(ident, owner); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.RemoveProjectile(ident, owner); + return true; + } + + return false; + } + + private static bool HandlePlayerKillMe(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + var direction = args.Data.ReadInt8(); + var dmg = args.Data.ReadInt16(); + var pvp = args.Data.ReadInt8() == 0; + if (OnKillMe(id, direction, dmg, pvp)) + return true; + int textlength = (int) (args.Data.Length - args.Data.Position - 1); + string deathtext = ""; + if (textlength > 0) + { + deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength)); + /*if (!TShock.Utils.ValidString(deathtext)) + { + return true; + }*/ + } + + args.Player.LastDeath = DateTime.Now; + args.Player.Dead = true; + + return false; + } + + private static bool HandleLiquidSet(GetDataHandlerArgs args) + { + int tileX = args.Data.ReadInt32(); + int tileY = args.Data.ReadInt32(); + byte liquid = args.Data.ReadInt8(); + bool lava = args.Data.ReadBoolean(); + + if (OnLiquidSet(tileX, tileY, liquid, lava)) + return true; + + //The liquid was picked up. + if (liquid == 0) + return false; + + if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) + return false; + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (args.Player.TileLiquidThreshold >= TShock.Config.TileLiquidThreshold) + { + args.Player.Disable("Reached TileLiquid threshold"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (!args.Player.Group.HasPermission(Permissions.ignoreliquidsetdetection)) + { + args.Player.TileLiquidThreshold++; + } + + int bucket = 0; + if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206) + { + bucket = 1; + } + else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 207) + { + bucket = 2; + } + + if (lava && bucket != 2 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)) + { + args.Player.Disable("Using banned lava bucket without permissions"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (!lava && bucket != 1 && !args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)) + { + args.Player.Disable("Using banned water bucket without permissions"); + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY, 16)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + return false; + } + + private static bool HandleTileKill(GetDataHandlerArgs args) + { + var tileX = args.Data.ReadInt32(); + var tileY = args.Data.ReadInt32(); + if (OnTileKill(tileX, tileY)) + return true; + if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) + return false; + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (Main.tile[tileX, tileY].type != 0x15 && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != 0)) //Chest + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (TShock.CheckTilePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + if (TShock.CheckRangePermission(args.Player, tileX, tileY)) + { + args.Player.SendTileSquare(tileX, tileY); + return true; + } + + return false; + } + + private static bool HandleSpawn(GetDataHandlerArgs args) + { + var player = args.Data.ReadInt8(); + var spawnx = args.Data.ReadInt32(); + var spawny = args.Data.ReadInt32(); + + if (OnPlayerSpawn(player, spawnx, spawny)) + return true; + + if (args.Player.InitSpawn && args.TPlayer.inventory[args.TPlayer.selectedItem].type != 50) + { + if (args.TPlayer.difficulty == 1 && (TShock.Config.KickOnMediumcoreDeath || TShock.Config.BanOnMediumcoreDeath)) + { + if (args.TPlayer.selectedItem != 50) + { + if (TShock.Config.BanOnMediumcoreDeath) + { + if (!TShock.Utils.Ban(args.Player, TShock.Config.MediumcoreBanReason)) + TShock.Utils.ForceKick(args.Player, "Death results in a ban, but can't ban you"); + } + else + { + TShock.Utils.ForceKick(args.Player, TShock.Config.MediumcoreKickReason); + } + return true; + } + } + } + else + args.Player.InitSpawn = true; + + args.Player.Dead = false; + return false; + } + + private static bool HandleChestOpen(GetDataHandlerArgs args) + { + var x = args.Data.ReadInt32(); + var y = args.Data.ReadInt32(); + + if (OnChestOpen(x, y)) + return true; + + if (TShock.CheckIgnores(args.Player)) + { + return true; + } + + if (TShock.CheckRangePermission(args.Player, x, y)) + { + return true; + } + + if (TShock.CheckTilePermission(args.Player, x, y) && TShock.Config.RegionProtectChests) + { + return true; + } + + return false; + } + + private static bool HandleChestItem(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt16(); + var slot = args.Data.ReadInt8(); + var stacks = args.Data.ReadInt8(); + var prefix = args.Data.ReadInt8(); + var type = args.Data.ReadInt16(); + + if (OnChestItemChange(id, slot, stacks, prefix, type)) + return true; + + if (args.TPlayer.chest != id) + { + return false; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.ChestItem, "", id, slot); + return true; + } + + Item item = new Item(); + item.netDefaults(type); + if (stacks > item.maxStack || TShock.Itembans.ItemIsBanned(item.name, args.Player)) + { + return false; + } + + if (TShock.CheckTilePermission(args.Player, Main.chest[id].x, Main.chest[id].y) && TShock.Config.RegionProtectChests) + { + return false; + } + + if (TShock.CheckRangePermission(args.Player, Main.chest[id].x, Main.chest[id].y)) + { + return false; + } + + return false; + } + + private static bool HandleSign(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt16(); + var x = args.Data.ReadInt32(); + var y = args.Data.ReadInt32(); + + if (OnSignEvent(id, x, y)) + return true; + + if (TShock.CheckTilePermission(args.Player, x, y)) + { + args.Player.SendData(PacketTypes.SignNew, "", id); + return true; + } + + if (TShock.CheckRangePermission(args.Player, x, y)) + { + args.Player.SendData(PacketTypes.SignNew, "", id); + return true; + } + return false; + } + + private static bool UpdateNPCHome(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt16(); + var x = args.Data.ReadInt16(); + var y = args.Data.ReadInt16(); + var homeless = args.Data.ReadInt8(); + + if (OnUpdateNPCHome(id, x, y, homeless)) + return true; + + if (!args.Player.Group.HasPermission(Permissions.movenpc)) + { + args.Player.SendMessage("You do not have permission to relocate NPCs.", Color.Red); + args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, + Convert.ToByte(Main.npc[id].homeless)); + return true; + } + + if (TShock.CheckTilePermission(args.Player, x, y)) + { + args.Player.SendMessage( "You do not have access to modify this area.", Color.Red); + args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, + Convert.ToByte(Main.npc[id].homeless)); + return true; + } + + //removed until NPC Home packet actually sends their home coords. + /*if (TShock.CheckRangePermission(args.Player, x, y)) + { + args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, + Convert.ToByte(Main.npc[id].homeless)); + return true; + }*/ + return false; + } + + private static bool HandlePlayerBuff(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + var type = args.Data.ReadInt8(); + var time = args.Data.ReadInt16(); + + if (OnPlayerBuff(id, type, time)) + return true; + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + return true; + } + if (!TShock.Players[id].TPlayer.hostile) + { + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + return true; + } + if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 50)) + { + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + return true; + } + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + return true; + } + + if (WhitelistBuffMaxTime[type] > 0 && time <= WhitelistBuffMaxTime[type]) + { + return false; + } + + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + return true; + } + + private static bool HandleItemDrop(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt16(); + var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); + var stacks = args.Data.ReadInt8(); + var prefix = args.Data.ReadInt8(); + var type = args.Data.ReadInt16(); + + if (OnItemDrop(id, pos, vel, stacks, prefix, type)) + return true; + + if (type == 0) //Item removed, let client do this to prevent item duplication client side + { + return false; + } + + if (TShock.CheckRangePermission(args.Player, (int) (pos.X/16f), (int) (pos.Y/16f))) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + return true; + } + + Item item = new Item(); + item.netDefaults(type); + if (stacks > item.maxStack || TShock.Itembans.ItemIsBanned(item.name, args.Player)) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + return true; + } + if ((TShock.Config.ServerSideInventory) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.Config.LogonDiscardThreshold)) + { + //Player is probably trying to sneak items onto the server in their hands!!! + Log.ConsoleInfo(string.Format("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.name)); + args.Player.SendData(PacketTypes.ItemDrop, "", id); + return true; + + } + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.ItemDrop, "", id); + return true; + } + + return false; + } + + private static bool HandlePlayerDamage(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + var direction = args.Data.ReadInt8(); + var dmg = args.Data.ReadInt16(); + var pvp = args.Data.ReadInt8(); + var crit = args.Data.ReadInt8(); + + if (OnPlayerDamage(id, direction, dmg, pvp, crit)) + return true; + + int textlength = (int) (args.Data.Length - args.Data.Position - 1); + string deathtext = ""; + if (textlength > 0) + { + deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength)); + /*if (!TShock.Utils.ValidString(deathtext)) + { + return true; + }*/ + } + + if (TShock.Players[id] == null) + return true; + + if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) + { + args.Player.Disable(String.Format("Player damage exceeded {0}", TShock.Config.MaxDamage ) ); + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + return true; + } + + if (!TShock.Players[id].TPlayer.hostile) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + return true; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + return true; + } + + if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + return true; + } + + return false; + } + + private static bool HandleNpcStrike(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + var direction = args.Data.ReadInt8(); + var dmg = args.Data.ReadInt16(); + var pvp = args.Data.ReadInt8(); + var crit = args.Data.ReadInt8(); + + if (OnNPCStrike(id, direction, dmg, pvp, crit)) + return true; + + if (Main.npc[id] == null) + return true; + + if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) + { + args.Player.Disable(String.Format("NPC damage exceeded {0}", TShock.Config.MaxDamage ) ); + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + return true; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + return true; + } + + if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.movenpc)) + { + args.Player.SendMessage( "You don't have permission to move the NPC", Color.Yellow); + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + return true; + } + + if (TShock.Config.RangeChecks && + TShock.CheckRangePermission(args.Player, (int) (Main.npc[id].position.X/16f), (int) (Main.npc[id].position.Y/16f), + 128)) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.NpcUpdate, "", id); + return true; + } + + return false; + } + + private static bool HandleSpecial(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + var type = args.Data.ReadInt8(); + + if (OnNPCSpecial(id, type)) + return true; + + if (type == 1 && TShock.Config.DisableDungeonGuardian) + { + args.Player.SendMessage("The Dungeon Guardian returned you to your spawn point", Color.Purple); + args.Player.Spawn(); + return true; + } + + return false; + } + + private static bool HandlePlayerAnimation(GetDataHandlerArgs args) + { + + if (OnPlayerAnimation()) + return true; + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + return true; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerAnimation, "", args.Player.Index); + return true; + } + + return false; + } + + private static bool HandlePlayerBuffUpdate(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt8(); + + if (OnPlayerBuffUpdate(id)) + return true; + + for (int i = 0; i < 10; i++) + { + var buff = args.Data.ReadInt8(); + + if (buff == 10) + { + if (!args.Player.Group.HasPermission(Permissions.usebanneditem) && + TShock.Itembans.ItemIsBanned("Invisibility Potion", args.Player)) + buff = 0; + else if (TShock.Config.DisableInvisPvP && args.TPlayer.hostile) + buff = 0; + } + + args.TPlayer.buffType[i] = buff; + if (args.TPlayer.buffType[i] > 0) + { + args.TPlayer.buffTime[i] = 60; + } + else + { + args.TPlayer.buffTime[i] = 0; + } + } + NetMessage.SendData((int) PacketTypes.PlayerBuff, -1, args.Player.Index, "", args.Player.Index); + return true; + } + + private static bool HandleSpawnBoss(GetDataHandlerArgs args) + { + var spawnboss = false; + var invasion = -1; + var plr = args.Data.ReadInt32(); + var Type = args.Data.ReadInt32(); + spawnboss = (Type == 4 || Type == 13 || (Type == 50 || Type == 125) || (Type == 126 || Type == 134 || (Type == (int) sbyte.MaxValue || Type == 128))); + if (!spawnboss) + { + switch (Type) + { + case -1: + invasion = 1; + break; + case -2: + invasion = 2; + break; + } + } + if (spawnboss && !args.Player.Group.HasPermission(Permissions.summonboss)) + { + args.Player.SendMessage("You don't have permission to summon a boss.", Color.Red); + return true; + } + if (invasion != -1 && !args.Player.Group.HasPermission(Permissions.startinvasion)) + { + args.Player.SendMessage("You don't have permission to start an invasion.", Color.Red); + return true; + } + if (!spawnboss && invasion == -1) + return true; + if (plr != args.Player.Index) + return true; + + string boss; + switch (Type) + { + case -2: + boss = "the Snow Legion"; + break; + case -1: + boss = "a Goblin Invasion"; + break; + case 4: + boss = "the Eye of Cthulhu"; + break; + case 13: + boss = "the Eater of Worlds"; + break; + case 50: + boss = "the King Slime"; + break; + case 125: + boss = "Retinazer"; + break; + case 126: + boss = "Spazmatism"; + break; + case 134: + boss = "the Destroyer"; + break; + case sbyte.MaxValue: + boss = "Skeleton Prime"; + break; + case 128: + boss = "Skeleton Prime"; + break; + default: + boss = "error"; + break; + } + + TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.Red); + return false; + } + } +} diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs index 8e36e51d9..65747689d 100644 --- a/TShockAPI/Group.cs +++ b/TShockAPI/Group.cs @@ -1,200 +1,200 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Linq; -using System.Collections.Generic; - -namespace TShockAPI -{ - public class Group - { - public readonly List permissions = new List(); - public readonly List negatedpermissions = new List(); - - public string Name { get; set; } - public Group Parent { get; set; } - public int Order { get; set; } - public string Prefix { get; set; } - public string Suffix { get; set; } - public string ParentName { get { return (null == Parent) ? "" : Parent.Name; } } - public string ChatColor - { - get { return string.Format("{0}{1}{2}", R.ToString("X2"), G.ToString("X2"), B.ToString("X2")); } - set - { - if (null != value) - { - string[] parts = value.Split(','); - if (3 == parts.Length) - { - byte r, g, b; - if (byte.TryParse(parts[0], out r) && byte.TryParse(parts[1], out g) && byte.TryParse(parts[2], out b)) - { - R = r; - G = g; - B = b; - return; - } - } - } - } - } - - public string Permissions - { - get - { - List all = new List(permissions); - negatedpermissions.ForEach(p => all.Add("!" + p)); - return string.Join(",", all); - } - set - { - permissions.Clear(); - negatedpermissions.Clear(); - if (null != value) - value.Split(',').ForEach(p => AddPermission(p.Trim())); - } - } - - public List TotalPermissions - { - get - { - var cur = this; - var traversed = new List(); - HashSet all = new HashSet(); - while (cur != null) - { - foreach (var perm in cur.permissions) - { - all.Add(perm); - } - - foreach (var perm in cur.negatedpermissions) - { - all.Remove(perm); - } - - if (traversed.Contains(cur)) - { - throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name)); - } - traversed.Add(cur); - cur = cur.Parent; - } - return all.ToList(); - } - } - - public byte R = 255; - public byte G = 255; - public byte B = 255; - - public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255", string permissions = null) - { - Name = groupname; - Parent = parentgroup; - ChatColor = chatcolor; - Permissions = permissions; - } - - public virtual bool HasPermission(string permission) - { - if (string.IsNullOrEmpty(permission)) - return true; - - var cur = this; - var traversed = new List(); - while (cur != null) - { - if (cur.negatedpermissions.Contains(permission)) - return false; - if (cur.permissions.Contains(permission)) - return true; - if (traversed.Contains(cur)) - { - throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name)); - } - traversed.Add(cur); - cur = cur.Parent; - } - return false; - } - - public void NegatePermission(string permission) - { - // Avoid duplicates - if (!negatedpermissions.Contains(permission)) - { - negatedpermissions.Add(permission); - permissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions - } - } - - public void AddPermission(string permission) - { - if (permission.StartsWith("!")) - { - NegatePermission(permission.Substring(1)); - return; - } - // Avoid duplicates - if (!permissions.Contains(permission)) - { - permissions.Add(permission); - negatedpermissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions - } - } - - public void SetPermission(List permission) - { - permissions.Clear(); - negatedpermissions.Clear(); - permission.ForEach(p => AddPermission(p)); - } - - public void RemovePermission(string permission) - { - if (permission.StartsWith("!")) - { - negatedpermissions.Remove(permission.Substring(1)); - return; - } - permissions.Remove(permission); - } - } - - public class SuperAdminGroup : Group - { - public SuperAdminGroup() - : base("superadmin") - { - R = (byte) TShock.Config.SuperAdminChatRGB[0]; - G = (byte) TShock.Config.SuperAdminChatRGB[1]; - B = (byte) TShock.Config.SuperAdminChatRGB[2]; - Prefix = TShock.Config.SuperAdminChatPrefix; - Suffix = TShock.Config.SuperAdminChatSuffix; - } - - public override bool HasPermission(string permission) - { - return true; - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Linq; +using System.Collections.Generic; + +namespace TShockAPI +{ + public class Group + { + public readonly List permissions = new List(); + public readonly List negatedpermissions = new List(); + + public string Name { get; set; } + public Group Parent { get; set; } + public int Order { get; set; } + public string Prefix { get; set; } + public string Suffix { get; set; } + public string ParentName { get { return (null == Parent) ? "" : Parent.Name; } } + public string ChatColor + { + get { return string.Format("{0}{1}{2}", R.ToString("X2"), G.ToString("X2"), B.ToString("X2")); } + set + { + if (null != value) + { + string[] parts = value.Split(','); + if (3 == parts.Length) + { + byte r, g, b; + if (byte.TryParse(parts[0], out r) && byte.TryParse(parts[1], out g) && byte.TryParse(parts[2], out b)) + { + R = r; + G = g; + B = b; + return; + } + } + } + } + } + + public string Permissions + { + get + { + List all = new List(permissions); + negatedpermissions.ForEach(p => all.Add("!" + p)); + return string.Join(",", all); + } + set + { + permissions.Clear(); + negatedpermissions.Clear(); + if (null != value) + value.Split(',').ForEach(p => AddPermission(p.Trim())); + } + } + + public List TotalPermissions + { + get + { + var cur = this; + var traversed = new List(); + HashSet all = new HashSet(); + while (cur != null) + { + foreach (var perm in cur.permissions) + { + all.Add(perm); + } + + foreach (var perm in cur.negatedpermissions) + { + all.Remove(perm); + } + + if (traversed.Contains(cur)) + { + throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name)); + } + traversed.Add(cur); + cur = cur.Parent; + } + return all.ToList(); + } + } + + public byte R = 255; + public byte G = 255; + public byte B = 255; + + public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255", string permissions = null) + { + Name = groupname; + Parent = parentgroup; + ChatColor = chatcolor; + Permissions = permissions; + } + + public virtual bool HasPermission(string permission) + { + if (string.IsNullOrEmpty(permission)) + return true; + + var cur = this; + var traversed = new List(); + while (cur != null) + { + if (cur.negatedpermissions.Contains(permission)) + return false; + if (cur.permissions.Contains(permission)) + return true; + if (traversed.Contains(cur)) + { + throw new Exception("Infinite group parenting ({0})".SFormat(cur.Name)); + } + traversed.Add(cur); + cur = cur.Parent; + } + return false; + } + + public void NegatePermission(string permission) + { + // Avoid duplicates + if (!negatedpermissions.Contains(permission)) + { + negatedpermissions.Add(permission); + permissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions + } + } + + public void AddPermission(string permission) + { + if (permission.StartsWith("!")) + { + NegatePermission(permission.Substring(1)); + return; + } + // Avoid duplicates + if (!permissions.Contains(permission)) + { + permissions.Add(permission); + negatedpermissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions + } + } + + public void SetPermission(List permission) + { + permissions.Clear(); + negatedpermissions.Clear(); + permission.ForEach(p => AddPermission(p)); + } + + public void RemovePermission(string permission) + { + if (permission.StartsWith("!")) + { + negatedpermissions.Remove(permission.Substring(1)); + return; + } + permissions.Remove(permission); + } + } + + public class SuperAdminGroup : Group + { + public SuperAdminGroup() + : base("superadmin") + { + R = (byte) TShock.Config.SuperAdminChatRGB[0]; + G = (byte) TShock.Config.SuperAdminChatRGB[1]; + B = (byte) TShock.Config.SuperAdminChatRGB[2]; + Prefix = TShock.Config.SuperAdminChatPrefix; + Suffix = TShock.Config.SuperAdminChatSuffix; + } + + public override bool HasPermission(string permission) + { + return true; + } + } } \ No newline at end of file diff --git a/TShockAPI/Rest/RestCommand.cs b/TShockAPI/Rest/RestCommand.cs index 13c6b1295..3e54a673b 100644 --- a/TShockAPI/Rest/RestCommand.cs +++ b/TShockAPI/Rest/RestCommand.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index edf5d8fe5..e653bffeb 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -298,7 +298,7 @@ private object UserInfoV2(RestVerbs verbs, IParameterCollection parameters) if (ret is RestObject) return ret; - User user = (User)ret; + User user = (User)ret; return new RestObject() { { "group", user.Group }, { "id", user.ID.ToString() }, { "name", user.Name } }; } diff --git a/TShockAPI/Rest/RestObject.cs b/TShockAPI/Rest/RestObject.cs index 130e2ec89..c2593f44d 100644 --- a/TShockAPI/Rest/RestObject.cs +++ b/TShockAPI/Rest/RestObject.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs index 8dd84f505..ddd9a2cd7 100644 --- a/TShockAPI/Rest/RestVerbs.cs +++ b/TShockAPI/Rest/RestVerbs.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 0dd7ff1f6..5444d8769 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -1,721 +1,721 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading; -using Terraria; -using TShockAPI.Net; - -namespace TShockAPI -{ - public class TSPlayer - { - public static readonly TSServerPlayer Server = new TSServerPlayer(); - public static readonly TSPlayer All = new TSPlayer("All"); - public int TileKillThreshold { get; set; } - public int TilePlaceThreshold { get; set; } - public int TileLiquidThreshold { get; set; } - public int ProjectileThreshold { get; set; } - public Dictionary TilesDestroyed { get; protected set; } - public Dictionary TilesCreated { get; protected set; } - public int FirstMaxHP { get; set; } - public int FirstMaxMP { get; set; } - public Group Group { get; set; } - public bool ReceivedInfo { get; set; } - public int Index { get; protected set; } - public DateTime LastPvpChange; - public Point[] TempPoints = new Point[2]; - public int AwaitingTempPoint { get; set; } - public bool AwaitingName { get; set; } - public DateTime LastThreat { get; set; } - public DateTime LastTileChangeNotify { get; set; } - public bool InitSpawn; - public bool DisplayLogs = true; - public Vector2 oldSpawn = Vector2.Zero; - public TSPlayer LastWhisper; - public int LoginAttempts { get; set; } - public Vector2 TeleportCoords = new Vector2(-1, -1); - public Vector2 LastNetPosition = Vector2.Zero; - public string UserAccountName { get; set; } - public bool HasBeenSpammedWithBuildMessage; - public bool IsLoggedIn; - public int UserID = -1; - public bool HasBeenNaggedAboutLoggingIn; - public bool TPAllow = true; - public bool mute; - public bool TpLock; - private Player FakePlayer; - public bool RequestedSection; - public DateTime LastDeath { get; set; } - public bool Dead; - public string Country = "??"; - public int Difficulty; - private string CacheIP; - public string IgnoreActionsForInventory = "none"; - public string IgnoreActionsForCheating = "none"; - public string IgnoreActionsForDisabledArmor = "none"; - public bool IgnoreActionsForClearingTrashCan; - public PlayerData PlayerData; - public bool RequiresPassword; - public bool SilentKickInProgress; - public List IceTiles; - public long RPm = 1; - public long WPm = 1; - public long SPm = 1; - public long BPm = 1; - public long LoginMS; - public bool LoginHarassed = false; - public bool RealPlayer - { - get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; } - } - - public bool ConnectionAlive - { - get - { - return RealPlayer && - (Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill); - } - } - - public int State - { - get { return Netplay.serverSock[Index].state; } - set { Netplay.serverSock[Index].state = value; } - } - - public string IP - { - get - { - if (string.IsNullOrEmpty(CacheIP)) - return - CacheIP = - RealPlayer - ? (Netplay.serverSock[Index].tcpClient.Connected - ? TShock.Utils.GetRealIP(Netplay.serverSock[Index].tcpClient.Client.RemoteEndPoint.ToString()) - : "") - : ""; - else - return CacheIP; - } - } - - /// - /// Terraria Player - /// - public Player TPlayer - { - get { return FakePlayer ?? Main.player[Index]; } - } - - public string Name - { - get { return TPlayer.name; } - } - - public bool Active - { - get { return TPlayer != null && TPlayer.active; } - } - - public int Team - { - get { return TPlayer.team; } - } - - public float X - { - get { return RealPlayer ? TPlayer.position.X : Main.spawnTileX*16; } - } - - public float Y - { - get { return RealPlayer ? TPlayer.position.Y : Main.spawnTileY*16; } - } - - public int TileX - { - get { return (int) (X/16); } - } - - public int TileY - { - get { return (int) (Y/16); } - } - - public bool InventorySlotAvailable - { - get - { - bool flag = false; - if (RealPlayer) - { - for (int i = 0; i < 40; i++) //41 is trash can, 42-45 is coins, 46-49 is ammo - { - if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "") - { - flag = true; - break; - } - } - } - return flag; - } - } - - public TSPlayer(int index) - { - TilesDestroyed = new Dictionary(); - TilesCreated = new Dictionary(); - Index = index; - Group = new Group(TShock.Config.DefaultGuestGroupName); - IceTiles = new List(); - } - - protected TSPlayer(String playerName) - { - TilesDestroyed = new Dictionary(); - TilesCreated = new Dictionary(); - Index = -1; - FakePlayer = new Player {name = playerName, whoAmi = -1}; - Group = new Group(TShock.Config.DefaultGuestGroupName); - } - - public virtual void Disconnect(string reason) - { - SendData(PacketTypes.Disconnect, reason); - } - - public virtual void Flush() - { - var sock = Netplay.serverSock[Index]; - if (sock == null) - return; - - TShock.PacketBuffer.Flush(sock); - } - - - private void SendWorldInfo(int tilex, int tiley, bool fakeid) - { - using (var ms = new MemoryStream()) - { - var msg = new WorldInfoMsg - { - Time = (int) Main.time, - DayTime = Main.dayTime, - MoonPhase = (byte) Main.moonPhase, - BloodMoon = Main.bloodMoon, - MaxTilesX = Main.maxTilesX, - MaxTilesY = Main.maxTilesY, - SpawnX = tilex, - SpawnY = tiley, - WorldSurface = (int) Main.worldSurface, - RockLayer = (int) Main.rockLayer, - //Sending a fake world id causes the client to not be able to find a stored spawnx/y. - //This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn. - WorldID = !fakeid ? Main.worldID : -1, - WorldFlags = (WorldGen.shadowOrbSmashed ? WorldInfoFlag.OrbSmashed : WorldInfoFlag.None) | - (NPC.downedBoss1 ? WorldInfoFlag.DownedBoss1 : WorldInfoFlag.None) | - (NPC.downedBoss2 ? WorldInfoFlag.DownedBoss2 : WorldInfoFlag.None) | - (NPC.downedBoss3 ? WorldInfoFlag.DownedBoss3 : WorldInfoFlag.None) | - (Main.hardMode ? WorldInfoFlag.HardMode : WorldInfoFlag.None) | - (NPC.downedClown ? WorldInfoFlag.DownedClown : WorldInfoFlag.None), - WorldName = Main.worldName - }; - msg.PackFull(ms); - SendRawData(ms.ToArray()); - } - } - - public bool Teleport(int tilex, int tiley) - { - InitSpawn = false; - - SendWorldInfo(tilex, tiley, true); - - //150 Should avoid all client crash errors - //The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks - //Try 300 if it does not work (Higher number - Longer load times - Less chance of error) - //Should we properly send sections so that clients don't get tiles twice? +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; +using Terraria; +using TShockAPI.Net; + +namespace TShockAPI +{ + public class TSPlayer + { + public static readonly TSServerPlayer Server = new TSServerPlayer(); + public static readonly TSPlayer All = new TSPlayer("All"); + public int TileKillThreshold { get; set; } + public int TilePlaceThreshold { get; set; } + public int TileLiquidThreshold { get; set; } + public int ProjectileThreshold { get; set; } + public Dictionary TilesDestroyed { get; protected set; } + public Dictionary TilesCreated { get; protected set; } + public int FirstMaxHP { get; set; } + public int FirstMaxMP { get; set; } + public Group Group { get; set; } + public bool ReceivedInfo { get; set; } + public int Index { get; protected set; } + public DateTime LastPvpChange; + public Point[] TempPoints = new Point[2]; + public int AwaitingTempPoint { get; set; } + public bool AwaitingName { get; set; } + public DateTime LastThreat { get; set; } + public DateTime LastTileChangeNotify { get; set; } + public bool InitSpawn; + public bool DisplayLogs = true; + public Vector2 oldSpawn = Vector2.Zero; + public TSPlayer LastWhisper; + public int LoginAttempts { get; set; } + public Vector2 TeleportCoords = new Vector2(-1, -1); + public Vector2 LastNetPosition = Vector2.Zero; + public string UserAccountName { get; set; } + public bool HasBeenSpammedWithBuildMessage; + public bool IsLoggedIn; + public int UserID = -1; + public bool HasBeenNaggedAboutLoggingIn; + public bool TPAllow = true; + public bool mute; + public bool TpLock; + private Player FakePlayer; + public bool RequestedSection; + public DateTime LastDeath { get; set; } + public bool Dead; + public string Country = "??"; + public int Difficulty; + private string CacheIP; + public string IgnoreActionsForInventory = "none"; + public string IgnoreActionsForCheating = "none"; + public string IgnoreActionsForDisabledArmor = "none"; + public bool IgnoreActionsForClearingTrashCan; + public PlayerData PlayerData; + public bool RequiresPassword; + public bool SilentKickInProgress; + public List IceTiles; + public long RPm = 1; + public long WPm = 1; + public long SPm = 1; + public long BPm = 1; + public long LoginMS; + public bool LoginHarassed = false; + public bool RealPlayer + { + get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; } + } + + public bool ConnectionAlive + { + get + { + return RealPlayer && + (Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill); + } + } + + public int State + { + get { return Netplay.serverSock[Index].state; } + set { Netplay.serverSock[Index].state = value; } + } + + public string IP + { + get + { + if (string.IsNullOrEmpty(CacheIP)) + return + CacheIP = + RealPlayer + ? (Netplay.serverSock[Index].tcpClient.Connected + ? TShock.Utils.GetRealIP(Netplay.serverSock[Index].tcpClient.Client.RemoteEndPoint.ToString()) + : "") + : ""; + else + return CacheIP; + } + } + + /// + /// Terraria Player + /// + public Player TPlayer + { + get { return FakePlayer ?? Main.player[Index]; } + } + + public string Name + { + get { return TPlayer.name; } + } + + public bool Active + { + get { return TPlayer != null && TPlayer.active; } + } + + public int Team + { + get { return TPlayer.team; } + } + + public float X + { + get { return RealPlayer ? TPlayer.position.X : Main.spawnTileX*16; } + } + + public float Y + { + get { return RealPlayer ? TPlayer.position.Y : Main.spawnTileY*16; } + } + + public int TileX + { + get { return (int) (X/16); } + } + + public int TileY + { + get { return (int) (Y/16); } + } + + public bool InventorySlotAvailable + { + get + { + bool flag = false; + if (RealPlayer) + { + for (int i = 0; i < 40; i++) //41 is trash can, 42-45 is coins, 46-49 is ammo + { + if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "") + { + flag = true; + break; + } + } + } + return flag; + } + } + + public TSPlayer(int index) + { + TilesDestroyed = new Dictionary(); + TilesCreated = new Dictionary(); + Index = index; + Group = new Group(TShock.Config.DefaultGuestGroupName); + IceTiles = new List(); + } + + protected TSPlayer(String playerName) + { + TilesDestroyed = new Dictionary(); + TilesCreated = new Dictionary(); + Index = -1; + FakePlayer = new Player {name = playerName, whoAmi = -1}; + Group = new Group(TShock.Config.DefaultGuestGroupName); + } + + public virtual void Disconnect(string reason) + { + SendData(PacketTypes.Disconnect, reason); + } + + public virtual void Flush() + { + var sock = Netplay.serverSock[Index]; + if (sock == null) + return; + + TShock.PacketBuffer.Flush(sock); + } + + + private void SendWorldInfo(int tilex, int tiley, bool fakeid) + { + using (var ms = new MemoryStream()) + { + var msg = new WorldInfoMsg + { + Time = (int) Main.time, + DayTime = Main.dayTime, + MoonPhase = (byte) Main.moonPhase, + BloodMoon = Main.bloodMoon, + MaxTilesX = Main.maxTilesX, + MaxTilesY = Main.maxTilesY, + SpawnX = tilex, + SpawnY = tiley, + WorldSurface = (int) Main.worldSurface, + RockLayer = (int) Main.rockLayer, + //Sending a fake world id causes the client to not be able to find a stored spawnx/y. + //This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn. + WorldID = !fakeid ? Main.worldID : -1, + WorldFlags = (WorldGen.shadowOrbSmashed ? WorldInfoFlag.OrbSmashed : WorldInfoFlag.None) | + (NPC.downedBoss1 ? WorldInfoFlag.DownedBoss1 : WorldInfoFlag.None) | + (NPC.downedBoss2 ? WorldInfoFlag.DownedBoss2 : WorldInfoFlag.None) | + (NPC.downedBoss3 ? WorldInfoFlag.DownedBoss3 : WorldInfoFlag.None) | + (Main.hardMode ? WorldInfoFlag.HardMode : WorldInfoFlag.None) | + (NPC.downedClown ? WorldInfoFlag.DownedClown : WorldInfoFlag.None), + WorldName = Main.worldName + }; + msg.PackFull(ms); + SendRawData(ms.ToArray()); + } + } + + public bool Teleport(int tilex, int tiley) + { + InitSpawn = false; + + SendWorldInfo(tilex, tiley, true); + + //150 Should avoid all client crash errors + //The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks + //Try 300 if it does not work (Higher number - Longer load times - Less chance of error) + //Should we properly send sections so that clients don't get tiles twice? SendTileSquare(tilex, tiley, 150); /* //We shouldn't need this section anymore -it can prevent otherwise acceptable teleportation under some circumstances. - if (!SendTileSquare(tilex, tiley, 150)) - { - InitSpawn = true; - SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); - return false; - } - + if (!SendTileSquare(tilex, tiley, 150)) + { + InitSpawn = true; + SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); + return false; + } + */ - Spawn(-1, -1); - - SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); - - TPlayer.position.X = (float)(tilex * 16 + 8 - TPlayer.width /2); - TPlayer.position.Y = (float)(tiley * 16 - TPlayer.height); - //We need to send the tile data again to prevent clients from thinking they *really* destroyed blocks just now. - - SendTileSquare(tilex, tiley, 150); - - return true; - } - - public void Spawn() - { - Spawn(TPlayer.SpawnX, TPlayer.SpawnY); - } - - public void Spawn(int tilex, int tiley) - { - using (var ms = new MemoryStream()) - { - var msg = new SpawnMsg - { - PlayerIndex = (byte) Index, - TileX = tilex, - TileY = tiley - }; - msg.PackFull(ms); - SendRawData(ms.ToArray()); - } - } - - public void RemoveProjectile(int index, int owner) - { - using (var ms = new MemoryStream()) - { - var msg = new ProjectileRemoveMsg - { - Index = (short) index, - Owner = (byte) owner - }; - msg.PackFull(ms); - SendRawData(ms.ToArray()); - } - } - - public virtual bool SendTileSquare(int x, int y, int size = 10) - { - try - { - int num = (size - 1)/2; - int m_x=0; - int m_y=0; - - if (x - num <0){ - m_x=0; - }else{ - m_x = x - num; - } - - if (y - num <0){ - m_y=0; - }else{ - m_y = y - num; - } - - if (m_x + size > Main.maxTilesX){ - m_x=Main.maxTilesX - size; - } - - if (m_y + size > Main.maxTilesY){ - m_y=Main.maxTilesY - size; - } - - SendData(PacketTypes.TileSendSquare, "", size, m_x, m_y); - return true; - } - catch (IndexOutOfRangeException) - { - - // This is expected if square exceeds array. - } - catch (Exception ex) - { - Log.Error(ex.ToString()); - } - return false; - } - - public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0) - { - int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix); - // This is for special pickaxe/hammers/swords etc - Main.item[itemid].SetDefaults(name); - // The set default overrides the wet and stack set by NewItem - Main.item[itemid].wet = Collision.WetCollision(Main.item[itemid].position, Main.item[itemid].width, - Main.item[itemid].height); - Main.item[itemid].stack = stack; - Main.item[itemid].owner = Index; - Main.item[itemid].prefix = (byte) prefix; - NetMessage.SendData((int) PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f); - NetMessage.SendData((int) PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f); - } - - public virtual void SendMessage(string msg) - { - SendMessage(msg, 0, 255, 0); - } - - public virtual void SendMessage(string msg, Color color) - { - SendMessage(msg, color.R, color.G, color.B); - } - - public virtual void SendMessage(string msg, byte red, byte green, byte blue) - { - SendData(PacketTypes.ChatText, msg, 255, red, green, blue); - } - - public virtual void DamagePlayer(int damage) - { - NetMessage.SendData((int) PacketTypes.PlayerDamage, -1, -1, "", Index, ((new Random()).Next(-1, 1)), damage, - (float) 0); - } - - public virtual void SetTeam(int team) - { - Main.player[Index].team = team; - SendData(PacketTypes.PlayerTeam, "", Index); - } - - public virtual void Disable(string reason = "") - { - LastThreat = DateTime.UtcNow; - SetBuff(33, 330, true); //Weak - SetBuff(32, 330, true); //Slow - SetBuff(23, 330, true); //Cursed - if (!string.IsNullOrEmpty(reason)) - Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}", Name, reason)); - - var trace = new StackTrace(); - StackFrame frame = null; - frame = trace.GetFrame(1); - if (frame != null && frame.GetMethod().DeclaringType != null) - Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable()"); - } - - public virtual void Whoopie(object time) - { - var time2 = (int) time; - var launch = DateTime.UtcNow; - var startname = Name; - SendMessage("You are now being annoyed.", Color.Red); - while ((DateTime.UtcNow - launch).TotalSeconds < time2 && startname == Name) - { - SendData(PacketTypes.NpcSpecial, number: Index, number2: 2f); - Thread.Sleep(50); - } - } - - public virtual void SetBuff(int type, int time = 3600, bool bypass = false) - { - if ((DateTime.UtcNow - LastThreat).TotalMilliseconds < 5000 && !bypass) - return; - - SendData(PacketTypes.PlayerAddBuff, number: Index, number2: type, number3: time); - } - - //Todo: Separate this into a few functions. SendTo, SendToAll, etc - public virtual void SendData(PacketTypes msgType, string text = "", int number = 0, float number2 = 0f, - float number3 = 0f, float number4 = 0f, int number5 = 0) - { - if (RealPlayer && !ConnectionAlive) - return; - - NetMessage.SendData((int) msgType, Index, -1, text, number, number2, number3, number4, number5); - } - - public virtual bool SendRawData(byte[] data) - { - if (!RealPlayer || !ConnectionAlive) - return false; - - return TShock.SendBytes(Netplay.serverSock[Index], data); - } - } - - public class TSRestPlayer : TSServerPlayer - { - internal List CommandReturn = new List(); - - public TSRestPlayer() - { - Group = new SuperAdminGroup(); - } - - public override void SendMessage(string msg) - { - SendMessage(msg, 0, 255, 0); - } - - public override void SendMessage(string msg, Color color) - { - SendMessage(msg, color.R, color.G, color.B); - } - - public override void SendMessage(string msg, byte red, byte green, byte blue) - { - CommandReturn.Add(msg); - } - - public List GetCommandOutput() - { - return CommandReturn; - } - } - - public class TSServerPlayer : TSPlayer - { - public TSServerPlayer() - : base("Server") - { - Group = new SuperAdminGroup(); - } - - public override void SendMessage(string msg) - { - SendMessage(msg, 0, 255, 0); - } - - public override void SendMessage(string msg, Color color) - { - SendMessage(msg, color.R, color.G, color.B); - } - - public override void SendMessage(string msg, byte red, byte green, byte blue) - { - Console.WriteLine(msg); - //RconHandler.Response += msg + "\n"; - } - - public void SetFullMoon(bool fullmoon) - { - Main.moonPhase = 0; - SetTime(false, 0); - } - - public void SetBloodMoon(bool bloodMoon) - { - Main.bloodMoon = bloodMoon; - SetTime(false, 0); - } - - public void SetTime(bool dayTime, double time) - { - Main.dayTime = dayTime; - Main.time = time; - NetMessage.SendData((int) PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); - NetMessage.syncPlayers(); - } - - public void SpawnNPC(int type, string name, int amount, int startTileX, int startTileY, int tileXRange = 100, - int tileYRange = 50) - { - for (int i = 0; i < amount; i++) - { - int spawnTileX; - int spawnTileY; - TShock.Utils.GetRandomClearTileWithInRange(startTileX, startTileY, tileXRange, tileYRange, out spawnTileX, - out spawnTileY); - int npcid = NPC.NewNPC(spawnTileX*16, spawnTileY*16, type, 0); - // This is for special slimes - Main.npc[npcid].SetDefaults(name); - } - } - - public void StrikeNPC(int npcid, int damage, float knockBack, int hitDirection) - { - Main.npc[npcid].StrikeNPC(damage, knockBack, hitDirection); - NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection); - } - - public void RevertTiles(Dictionary tiles) - { - // Update Main.Tile first so that when tile sqaure is sent it is correct - foreach (KeyValuePair entry in tiles) - { - Main.tile[(int) entry.Key.X, (int) entry.Key.Y].Data = entry.Value; - } - // Send all players updated tile sqaures - foreach (Vector2 coords in tiles.Keys) - { - All.SendTileSquare((int) coords.X, (int) coords.Y, 3); - } - } - } - - public class PlayerData - { - public NetItem[] inventory = new NetItem[NetItem.maxNetInventory]; - public int maxHealth = 100; - //public int maxMana = 100; - public bool exists; - - public PlayerData(TSPlayer player) - { - for (int i = 0; i < NetItem.maxNetInventory; i++) - { - this.inventory[i] = new NetItem(); - } - this.inventory[0].netID = -15; - this.inventory[0].stack = 1; - if (player.TPlayer.inventory[0] != null && player.TPlayer.inventory[0].netID == -15) - this.inventory[0].prefix = player.TPlayer.inventory[0].prefix; - this.inventory[1].netID = -13; - this.inventory[1].stack = 1; - if (player.TPlayer.inventory[1] != null && player.TPlayer.inventory[1].netID == -13) - this.inventory[1].prefix = player.TPlayer.inventory[1].prefix; - this.inventory[2].netID = -16; - this.inventory[2].stack = 1; - if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16) - this.inventory[2].prefix = player.TPlayer.inventory[2].prefix; - } - - public void StoreSlot(int slot, int netID, int prefix, int stack) - { - if(slot > (this.inventory.Length - 1)) //if the slot is out of range then dont save - { - return; - } - - this.inventory[slot].netID = netID; - if (this.inventory[slot].netID != 0) - { - this.inventory[slot].stack = stack; - this.inventory[slot].prefix = prefix; - } - else - { - this.inventory[slot].stack = 0; - this.inventory[slot].prefix = 0; - } - } - - public void CopyInventory(TSPlayer player) - { - this.maxHealth = player.TPlayer.statLifeMax; - Item[] inventory = player.TPlayer.inventory; - Item[] armor = player.TPlayer.armor; - for (int i = 0; i < NetItem.maxNetInventory; i++) - { - if (i < 49) - { - if (player.TPlayer.inventory[i] != null) - { - this.inventory[i].netID = inventory[i].netID; - } - else - { - this.inventory[i].netID = 0; - } - - if (this.inventory[i].netID != 0) - { - this.inventory[i].stack = inventory[i].stack; - this.inventory[i].prefix = inventory[i].prefix; - } - else - { - this.inventory[i].stack = 0; - this.inventory[i].prefix = 0; - } - } - else - { - if (player.TPlayer.armor[i - 48] != null) - { - this.inventory[i].netID = armor[i - 48].netID; - } - else - { - this.inventory[i].netID = 0; - } - - if (this.inventory[i].netID != 0) - { - this.inventory[i].stack = armor[i - 48].stack; - this.inventory[i].prefix = armor[i - 48].prefix; - } - else - { - this.inventory[i].stack = 0; - this.inventory[i].prefix = 0; - } - } - } - } - } - - public class NetItem - { - public static int maxNetInventory = 59; - public int netID; - public int stack; - public int prefix; - - public static string ToString(NetItem[] inventory) - { - string inventoryString = ""; - for (int i = 0; i < maxNetInventory; i++) - { - if (i != 0) - inventoryString += "~"; - inventoryString += inventory[i].netID; - if (inventory[i].netID != 0) - { - inventoryString += "," + inventory[i].stack; - inventoryString += "," + inventory[i].prefix; - } - else - { - inventoryString += ",0,0"; - } - } - return inventoryString; - } - - public static NetItem[] Parse(string data) - { - NetItem[] inventory = new NetItem[maxNetInventory]; - int i; - for (i = 0; i < maxNetInventory; i++) - { - inventory[i] = new NetItem(); - } - string[] items = data.Split('~'); - i = 0; - foreach (string item in items) - { - string[] idata = item.Split(','); - inventory[i].netID = int.Parse(idata[0]); - inventory[i].stack = int.Parse(idata[1]); - inventory[i].prefix = int.Parse(idata[2]); - i++; - } - return inventory; - } - } -} + Spawn(-1, -1); + + SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); + + TPlayer.position.X = (float)(tilex * 16 + 8 - TPlayer.width /2); + TPlayer.position.Y = (float)(tiley * 16 - TPlayer.height); + //We need to send the tile data again to prevent clients from thinking they *really* destroyed blocks just now. + + SendTileSquare(tilex, tiley, 150); + + return true; + } + + public void Spawn() + { + Spawn(TPlayer.SpawnX, TPlayer.SpawnY); + } + + public void Spawn(int tilex, int tiley) + { + using (var ms = new MemoryStream()) + { + var msg = new SpawnMsg + { + PlayerIndex = (byte) Index, + TileX = tilex, + TileY = tiley + }; + msg.PackFull(ms); + SendRawData(ms.ToArray()); + } + } + + public void RemoveProjectile(int index, int owner) + { + using (var ms = new MemoryStream()) + { + var msg = new ProjectileRemoveMsg + { + Index = (short) index, + Owner = (byte) owner + }; + msg.PackFull(ms); + SendRawData(ms.ToArray()); + } + } + + public virtual bool SendTileSquare(int x, int y, int size = 10) + { + try + { + int num = (size - 1)/2; + int m_x=0; + int m_y=0; + + if (x - num <0){ + m_x=0; + }else{ + m_x = x - num; + } + + if (y - num <0){ + m_y=0; + }else{ + m_y = y - num; + } + + if (m_x + size > Main.maxTilesX){ + m_x=Main.maxTilesX - size; + } + + if (m_y + size > Main.maxTilesY){ + m_y=Main.maxTilesY - size; + } + + SendData(PacketTypes.TileSendSquare, "", size, m_x, m_y); + return true; + } + catch (IndexOutOfRangeException) + { + + // This is expected if square exceeds array. + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + return false; + } + + public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0) + { + int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix); + // This is for special pickaxe/hammers/swords etc + Main.item[itemid].SetDefaults(name); + // The set default overrides the wet and stack set by NewItem + Main.item[itemid].wet = Collision.WetCollision(Main.item[itemid].position, Main.item[itemid].width, + Main.item[itemid].height); + Main.item[itemid].stack = stack; + Main.item[itemid].owner = Index; + Main.item[itemid].prefix = (byte) prefix; + NetMessage.SendData((int) PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f); + NetMessage.SendData((int) PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f); + } + + public virtual void SendMessage(string msg) + { + SendMessage(msg, 0, 255, 0); + } + + public virtual void SendMessage(string msg, Color color) + { + SendMessage(msg, color.R, color.G, color.B); + } + + public virtual void SendMessage(string msg, byte red, byte green, byte blue) + { + SendData(PacketTypes.ChatText, msg, 255, red, green, blue); + } + + public virtual void DamagePlayer(int damage) + { + NetMessage.SendData((int) PacketTypes.PlayerDamage, -1, -1, "", Index, ((new Random()).Next(-1, 1)), damage, + (float) 0); + } + + public virtual void SetTeam(int team) + { + Main.player[Index].team = team; + SendData(PacketTypes.PlayerTeam, "", Index); + } + + public virtual void Disable(string reason = "") + { + LastThreat = DateTime.UtcNow; + SetBuff(33, 330, true); //Weak + SetBuff(32, 330, true); //Slow + SetBuff(23, 330, true); //Cursed + if (!string.IsNullOrEmpty(reason)) + Log.ConsoleInfo(string.Format("Player {0} has been disabled for {1}", Name, reason)); + + var trace = new StackTrace(); + StackFrame frame = null; + frame = trace.GetFrame(1); + if (frame != null && frame.GetMethod().DeclaringType != null) + Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable()"); + } + + public virtual void Whoopie(object time) + { + var time2 = (int) time; + var launch = DateTime.UtcNow; + var startname = Name; + SendMessage("You are now being annoyed.", Color.Red); + while ((DateTime.UtcNow - launch).TotalSeconds < time2 && startname == Name) + { + SendData(PacketTypes.NpcSpecial, number: Index, number2: 2f); + Thread.Sleep(50); + } + } + + public virtual void SetBuff(int type, int time = 3600, bool bypass = false) + { + if ((DateTime.UtcNow - LastThreat).TotalMilliseconds < 5000 && !bypass) + return; + + SendData(PacketTypes.PlayerAddBuff, number: Index, number2: type, number3: time); + } + + //Todo: Separate this into a few functions. SendTo, SendToAll, etc + public virtual void SendData(PacketTypes msgType, string text = "", int number = 0, float number2 = 0f, + float number3 = 0f, float number4 = 0f, int number5 = 0) + { + if (RealPlayer && !ConnectionAlive) + return; + + NetMessage.SendData((int) msgType, Index, -1, text, number, number2, number3, number4, number5); + } + + public virtual bool SendRawData(byte[] data) + { + if (!RealPlayer || !ConnectionAlive) + return false; + + return TShock.SendBytes(Netplay.serverSock[Index], data); + } + } + + public class TSRestPlayer : TSServerPlayer + { + internal List CommandReturn = new List(); + + public TSRestPlayer() + { + Group = new SuperAdminGroup(); + } + + public override void SendMessage(string msg) + { + SendMessage(msg, 0, 255, 0); + } + + public override void SendMessage(string msg, Color color) + { + SendMessage(msg, color.R, color.G, color.B); + } + + public override void SendMessage(string msg, byte red, byte green, byte blue) + { + CommandReturn.Add(msg); + } + + public List GetCommandOutput() + { + return CommandReturn; + } + } + + public class TSServerPlayer : TSPlayer + { + public TSServerPlayer() + : base("Server") + { + Group = new SuperAdminGroup(); + } + + public override void SendMessage(string msg) + { + SendMessage(msg, 0, 255, 0); + } + + public override void SendMessage(string msg, Color color) + { + SendMessage(msg, color.R, color.G, color.B); + } + + public override void SendMessage(string msg, byte red, byte green, byte blue) + { + Console.WriteLine(msg); + //RconHandler.Response += msg + "\n"; + } + + public void SetFullMoon(bool fullmoon) + { + Main.moonPhase = 0; + SetTime(false, 0); + } + + public void SetBloodMoon(bool bloodMoon) + { + Main.bloodMoon = bloodMoon; + SetTime(false, 0); + } + + public void SetTime(bool dayTime, double time) + { + Main.dayTime = dayTime; + Main.time = time; + NetMessage.SendData((int) PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); + NetMessage.syncPlayers(); + } + + public void SpawnNPC(int type, string name, int amount, int startTileX, int startTileY, int tileXRange = 100, + int tileYRange = 50) + { + for (int i = 0; i < amount; i++) + { + int spawnTileX; + int spawnTileY; + TShock.Utils.GetRandomClearTileWithInRange(startTileX, startTileY, tileXRange, tileYRange, out spawnTileX, + out spawnTileY); + int npcid = NPC.NewNPC(spawnTileX*16, spawnTileY*16, type, 0); + // This is for special slimes + Main.npc[npcid].SetDefaults(name); + } + } + + public void StrikeNPC(int npcid, int damage, float knockBack, int hitDirection) + { + Main.npc[npcid].StrikeNPC(damage, knockBack, hitDirection); + NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection); + } + + public void RevertTiles(Dictionary tiles) + { + // Update Main.Tile first so that when tile sqaure is sent it is correct + foreach (KeyValuePair entry in tiles) + { + Main.tile[(int) entry.Key.X, (int) entry.Key.Y].Data = entry.Value; + } + // Send all players updated tile sqaures + foreach (Vector2 coords in tiles.Keys) + { + All.SendTileSquare((int) coords.X, (int) coords.Y, 3); + } + } + } + + public class PlayerData + { + public NetItem[] inventory = new NetItem[NetItem.maxNetInventory]; + public int maxHealth = 100; + //public int maxMana = 100; + public bool exists; + + public PlayerData(TSPlayer player) + { + for (int i = 0; i < NetItem.maxNetInventory; i++) + { + this.inventory[i] = new NetItem(); + } + this.inventory[0].netID = -15; + this.inventory[0].stack = 1; + if (player.TPlayer.inventory[0] != null && player.TPlayer.inventory[0].netID == -15) + this.inventory[0].prefix = player.TPlayer.inventory[0].prefix; + this.inventory[1].netID = -13; + this.inventory[1].stack = 1; + if (player.TPlayer.inventory[1] != null && player.TPlayer.inventory[1].netID == -13) + this.inventory[1].prefix = player.TPlayer.inventory[1].prefix; + this.inventory[2].netID = -16; + this.inventory[2].stack = 1; + if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16) + this.inventory[2].prefix = player.TPlayer.inventory[2].prefix; + } + + public void StoreSlot(int slot, int netID, int prefix, int stack) + { + if(slot > (this.inventory.Length - 1)) //if the slot is out of range then dont save + { + return; + } + + this.inventory[slot].netID = netID; + if (this.inventory[slot].netID != 0) + { + this.inventory[slot].stack = stack; + this.inventory[slot].prefix = prefix; + } + else + { + this.inventory[slot].stack = 0; + this.inventory[slot].prefix = 0; + } + } + + public void CopyInventory(TSPlayer player) + { + this.maxHealth = player.TPlayer.statLifeMax; + Item[] inventory = player.TPlayer.inventory; + Item[] armor = player.TPlayer.armor; + for (int i = 0; i < NetItem.maxNetInventory; i++) + { + if (i < 49) + { + if (player.TPlayer.inventory[i] != null) + { + this.inventory[i].netID = inventory[i].netID; + } + else + { + this.inventory[i].netID = 0; + } + + if (this.inventory[i].netID != 0) + { + this.inventory[i].stack = inventory[i].stack; + this.inventory[i].prefix = inventory[i].prefix; + } + else + { + this.inventory[i].stack = 0; + this.inventory[i].prefix = 0; + } + } + else + { + if (player.TPlayer.armor[i - 48] != null) + { + this.inventory[i].netID = armor[i - 48].netID; + } + else + { + this.inventory[i].netID = 0; + } + + if (this.inventory[i].netID != 0) + { + this.inventory[i].stack = armor[i - 48].stack; + this.inventory[i].prefix = armor[i - 48].prefix; + } + else + { + this.inventory[i].stack = 0; + this.inventory[i].prefix = 0; + } + } + } + } + } + + public class NetItem + { + public static int maxNetInventory = 59; + public int netID; + public int stack; + public int prefix; + + public static string ToString(NetItem[] inventory) + { + string inventoryString = ""; + for (int i = 0; i < maxNetInventory; i++) + { + if (i != 0) + inventoryString += "~"; + inventoryString += inventory[i].netID; + if (inventory[i].netID != 0) + { + inventoryString += "," + inventory[i].stack; + inventoryString += "," + inventory[i].prefix; + } + else + { + inventoryString += ",0,0"; + } + } + return inventoryString; + } + + public static NetItem[] Parse(string data) + { + NetItem[] inventory = new NetItem[maxNetInventory]; + int i; + for (i = 0; i < maxNetInventory; i++) + { + inventory[i] = new NetItem(); + } + string[] items = data.Split('~'); + i = 0; + foreach (string item in items) + { + string[] idata = item.Split(','); + inventory[i].netID = int.Parse(idata[0]); + inventory[i].stack = int.Parse(idata[1]); + inventory[i].prefix = int.Parse(idata[2]); + i++; + } + return inventory; + } + } +} diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 218b9d879..78c56be65 100755 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1,1467 +1,1467 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Net; -using System.Reflection; -using System.Threading; -using Hooks; -using MaxMind; -using Mono.Data.Sqlite; -using MySql.Data.MySqlClient; -using Rests; -using Terraria; -using TShockAPI.DB; -using TShockAPI.Net; - -namespace TShockAPI -{ - [APIVersion(1, 11)] - public class TShock : TerrariaPlugin - { - public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; - public static readonly string VersionCodename = "Squashing bugs, and adding suggestions"; - - public static string SavePath = "tshock"; - - public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers]; - public static BanManager Bans; - public static WarpManager Warps; - public static RegionManager Regions; - public static BackupManager Backups; - public static GroupManager Groups; - public static UserManager Users; - public static ItemManager Itembans; - public static RemeberedPosManager RememberedPos; - public static InventoryManager InventoryDB; - public static ConfigFile Config { get; set; } - public static IDbConnection DB; - public static bool OverridePort; - public static PacketBufferer PacketBuffer; - public static GeoIPCountry Geo; - public static SecureRest RestApi; - public static RestManager RestManager; - public static Utils Utils = Utils.Instance; - public static StatTracker StatTracker = new StatTracker(); - /// - /// Used for implementing REST Tokens prior to the REST system starting up. - /// - public static Dictionary RESTStartupTokens = new Dictionary(); - - /// - /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. - /// - public static event Action Initialized; - - - public override Version Version - { - get { return VersionNum; } - } - - public override string Name - { - get { return "TShock"; } - } - - public override string Author - { - get { return "The Nyx Team"; } - } - - public override string Description - { - get { return "The administration modification of the future."; } - } - - public TShock(Main game) - : base(game) - { - Config = new ConfigFile(); - Order = 0; - } - - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public override void Initialize() - { - HandleCommandLine(Environment.GetCommandLineArgs()); - - if (!Directory.Exists(SavePath)) - Directory.CreateDirectory(SavePath); - - DateTime now = DateTime.Now; -#if DEBUG - Log.Initialize(Path.Combine(SavePath, now.ToString("yyyyMMddHHmmss")+".log"), LogLevel.All, false); -#else - Log.Initialize(Path.Combine(SavePath, now.ToString("yyyyMMddHHmmss")+".log"), LogLevel.All & ~LogLevel.Debug, false); -#endif - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - - try - { - if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) - { - Log.ConsoleInfo( - "TShock was improperly shut down. Please avoid this in the future, world corruption may result from this."); - File.Delete(Path.Combine(SavePath, "tshock.pid")); - } - File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture)); - - ConfigFile.ConfigRead += OnConfigRead; - FileTools.SetupConfig(); - - HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); - - if (Config.StorageType.ToLower() == "sqlite") - { - string sql = Path.Combine(SavePath, "tshock.sqlite"); - DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql)); - } - else if (Config.StorageType.ToLower() == "mysql") - { - try - { - var hostport = Config.MySqlHost.Split(':'); - DB = new MySqlConnection(); - DB.ConnectionString = - String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", - hostport[0], - hostport.Length > 1 ? hostport[1] : "3306", - Config.MySqlDbName, - Config.MySqlUsername, - Config.MySqlPassword - ); - } - catch (MySqlException ex) - { - Log.Error(ex.ToString()); - throw new Exception("MySql not setup correctly"); - } - } - else - { - throw new Exception("Invalid storage type"); - } - - Backups = new BackupManager(Path.Combine(SavePath, "backups")); - Backups.KeepFor = Config.BackupKeepFor; - Backups.Interval = Config.BackupInterval; - Bans = new BanManager(DB); - Warps = new WarpManager(DB); - Users = new UserManager(DB); - Groups = new GroupManager(DB); - Regions = new RegionManager(DB); - Itembans = new ItemManager(DB); - RememberedPos = new RemeberedPosManager(DB); - InventoryDB = new InventoryManager(DB); - RestApi = new SecureRest(Netplay.serverListenIP, Config.RestApiPort); - RestApi.Verify += RestApi_Verify; - RestApi.Port = Config.RestApiPort; - RestManager = new RestManager(RestApi); - RestManager.RegisterRestfulCommands(); - - var geoippath = Path.Combine(SavePath, "GeoIP.dat"); - if (Config.EnableGeoIP && File.Exists(geoippath)) - Geo = new GeoIPCountry(geoippath); - - Log.ConsoleInfo(string.Format("TerrariaShock Version {0} ({1}) now running.", Version, VersionCodename)); - - GameHooks.PostInitialize += OnPostInit; - GameHooks.Update += OnUpdate; - ServerHooks.Connect += OnConnect; - ServerHooks.Join += OnJoin; - ServerHooks.Leave += OnLeave; - ServerHooks.Chat += OnChat; - ServerHooks.Command += ServerHooks_OnCommand; - NetHooks.GetData += OnGetData; - NetHooks.SendData += NetHooks_SendData; - NetHooks.GreetPlayer += OnGreetPlayer; - NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc; - NpcHooks.SetDefaultsInt += OnNpcSetDefaults; - ProjectileHooks.SetDefaults += OnProjectileSetDefaults; - WorldHooks.StartHardMode += OnStartHardMode; - WorldHooks.SaveWorld += SaveManager.Instance.OnSaveWorld; - - GetDataHandlers.InitGetDataHandler(); - Commands.InitCommands(); - //RconHandler.StartThread(); - - if (Config.RestApiEnabled) - RestApi.Start(); - - if (Config.BufferPackets) - PacketBuffer = new PacketBufferer(); - - Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); - Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled")); - - if (Initialized != null) - Initialized(); - } - catch (Exception ex) - { - Log.Error("Fatal Startup Exception"); - Log.Error(ex.ToString()); - Environment.Exit(1); - } - } - - private RestObject RestApi_Verify(string username, string password) - { - var userAccount = Users.GetUserByName(username); - if (userAccount == null) - { - return new RestObject("401") - {Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."}; - } - - if (Utils.HashPassword(password).ToUpper() != userAccount.Password.ToUpper()) - { - return new RestObject("401") - {Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."}; - } - - if (!Utils.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") - { - return new RestObject("403") - { - Error = - "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)" - }; - } - - return new RestObject("200") {Response = "Successful login"}; //Maybe return some user info too? - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - // NOTE: order is important here - if (Geo != null) - { - Geo.Dispose(); - } - SaveManager.Instance.Dispose(); - - GameHooks.PostInitialize -= OnPostInit; - GameHooks.Update -= OnUpdate; - ServerHooks.Connect -= OnConnect; - ServerHooks.Join -= OnJoin; - ServerHooks.Leave -= OnLeave; - ServerHooks.Chat -= OnChat; - ServerHooks.Command -= ServerHooks_OnCommand; - NetHooks.GetData -= OnGetData; - NetHooks.SendData -= NetHooks_SendData; - NetHooks.GreetPlayer -= OnGreetPlayer; - NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; - NpcHooks.SetDefaultsInt -= OnNpcSetDefaults; - ProjectileHooks.SetDefaults -= OnProjectileSetDefaults; - WorldHooks.StartHardMode -= OnStartHardMode; - WorldHooks.SaveWorld -= SaveManager.Instance.OnSaveWorld; - - if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) - { - File.Delete(Path.Combine(SavePath, "tshock.pid")); - } - - RestApi.Dispose(); - Log.Dispose(); - } - base.Dispose(disposing); - } - - /// - /// Handles exceptions that we didn't catch or that Red fucked up - /// - /// - /// - private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - Log.Error(e.ExceptionObject.ToString()); - - if (e.ExceptionObject.ToString().Contains("Terraria.Netplay.ListenForClients") || - e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop")) - { - var sb = new List(); - for (int i = 0; i < Netplay.serverSock.Length; i++) - { - if (Netplay.serverSock[i] == null) - { - sb.Add("Sock[" + i + "]"); - } - else if (Netplay.serverSock[i].tcpClient == null) - { - sb.Add("Tcp[" + i + "]"); - } - } - Log.Error(string.Join(", ", sb)); - } - - if (e.IsTerminating) - { - if (Main.worldPathName != null && Config.SaveWorldOnCrash) - { - Main.worldPathName += ".crash"; - SaveManager.Instance.SaveWorld(); - } - } - } - - private void HandleCommandLine(string[] parms) - { - for (int i = 0; i < parms.Length; i++) - { - if (parms[i].ToLower() == "-configpath") - { - var path = parms[++i]; - if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) - { - SavePath = path; - Log.ConsoleInfo("Config path has been set to " + path); - } - } - if (parms[i].ToLower() == "-worldpath") - { - var path = parms[++i]; - if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) - { - Main.WorldPath = path; - Log.ConsoleInfo("World path has been set to " + path); - } - } - if (parms[i].ToLower() == "-dump") - { - ConfigFile.DumpDescriptions(); - Permissions.DumpDescriptions(); - } - } - } - - public static void HandleCommandLinePostConfigLoad(string[] parms) - { - for (int i = 0; i < parms.Length; i++) - { - switch(parms[i].ToLower()) - { - case "-port": - int port = Convert.ToInt32(parms[++i]); - Netplay.serverPort = port; - Config.ServerPort = port; - OverridePort = true; - Log.ConsoleInfo("Port overridden by startup argument. Set to " + port); - break; - case "-rest-token": - string token = Convert.ToString(parms[++i]); - RESTStartupTokens.Add(token, "null"); - Console.WriteLine("Startup parameter overrode REST token."); - break; - case "-rest-enabled": - Config.RestApiEnabled = Convert.ToBoolean(parms[++i]); - Console.WriteLine("Startup parameter overrode REST enable."); - break; - case "-rest-port": - Config.RestApiPort = Convert.ToInt32(parms[++i]); - Console.WriteLine("Startup parameter overrode REST port."); - break; - case "-maxplayers": - case "-players": - Config.MaxSlots = Convert.ToInt32(parms[++i]); - Console.WriteLine("Startup parameter overrode maximum player slot configuration value."); - break; - } - } - } - - /* - * Hooks: - * - */ - - public static int AuthToken = -1; - - private void OnPostInit() - { - SetConsoleTitle(); - if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt"))) - { - var r = new Random((int) DateTime.Now.ToBinary()); - AuthToken = r.Next(100000, 10000000); - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " + AuthToken); - Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); - Console.ForegroundColor = ConsoleColor.Gray; - FileTools.CreateFile(Path.Combine(SavePath, "authcode.txt")); - using (var tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt"))) - { - tw.WriteLine(AuthToken); - } - } - else if (File.Exists(Path.Combine(SavePath, "authcode.txt"))) - { - using (var tr = new StreamReader(Path.Combine(SavePath, "authcode.txt"))) - { - AuthToken = Convert.ToInt32(tr.ReadLine()); - } - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine( - "TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used."); - Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken); - Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); - Console.ForegroundColor = ConsoleColor.Gray; - } - else - { - AuthToken = 0; - } - Regions.ReloadAllRegions(); - - StatTracker.CheckIn(); - FixChestStacks(); - } - - private void FixChestStacks() - { - foreach (Chest chest in Main.chest) - { - if (chest != null) - { - foreach (Item item in chest.item) - { - if (item != null && item.stack > item.maxStack) - item.stack = item.maxStack; - } - } - } - } - - private DateTime LastCheck = DateTime.UtcNow; - private DateTime LastSave = DateTime.UtcNow; - - private void OnUpdate() - { - UpdateManager.UpdateProcedureCheck(); - StatTracker.CheckIn(); - if (Backups.IsBackupTime) - Backups.Backup(); - //call these every second, not every update - if ((DateTime.UtcNow - LastCheck).TotalSeconds >= 1) - { - OnSecondUpdate(); - LastCheck = DateTime.UtcNow; - } - - if ((DateTime.UtcNow - LastSave).TotalMinutes >= Config.ServerSideInventorySave) - { - foreach (TSPlayer player in Players) - { - // prevent null point exceptions - if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan) - { - - InventoryDB.InsertPlayerData(player); - } - } - LastSave = DateTime.UtcNow; - } - } - - private void OnSecondUpdate() - { - if (Config.ForceTime != "normal") - { - switch (Config.ForceTime) - { - case "day": - TSPlayer.Server.SetTime(true, 27000.0); - break; - case "night": - TSPlayer.Server.SetTime(false, 16200.0); - break; - } - } - int count = 0; - foreach (TSPlayer player in Players) - { - if (player != null && player.Active) - { - count++; - if (player.TilesDestroyed != null) - { - if (player.TileKillThreshold >= Config.TileKillThreshold) - { - player.Disable("Reached TileKill threshold"); - TSPlayer.Server.RevertTiles(player.TilesDestroyed); - player.TilesDestroyed.Clear(); - } - } - if (player.TileKillThreshold > 0) - { - player.TileKillThreshold = 0; - //We don't want to revert the entire map in case of a disable. - player.TilesDestroyed.Clear(); - } - if (player.TilesCreated != null) - { - if (player.TilePlaceThreshold >= Config.TilePlaceThreshold) - { - player.Disable("Reached TilePlace threshold"); - TSPlayer.Server.RevertTiles(player.TilesCreated); - player.TilesCreated.Clear(); - } - } - if (player.TilePlaceThreshold > 0) - { - player.TilePlaceThreshold = 0; - } - if (player.TileLiquidThreshold >= Config.TileLiquidThreshold) - { - player.Disable("Reached TileLiquid threshold"); - } - if (player.TileLiquidThreshold > 0) - { - player.TileLiquidThreshold = 0; - } - if (player.ProjectileThreshold >= Config.ProjectileThreshold) - { - player.Disable("Reached Projectile threshold"); - } - if (player.ProjectileThreshold > 0) - { - player.ProjectileThreshold = 0; - } - if (player.Dead && (DateTime.Now - player.LastDeath).Seconds >= 3 && player.Difficulty != 2) - { - player.Spawn(); - } - string check = "none"; - foreach (Item item in player.TPlayer.inventory) - { - if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && item.stack > item.maxStack && - item.type != 0) - { - check = "Remove Item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack; - } - } - player.IgnoreActionsForCheating = check; - check = "none"; - foreach (Item item in player.TPlayer.armor) - { - if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(item.name, player)) - { - player.SetBuff(30, 120); //Bleeding - player.SetBuff(36, 120); //Broken Armor - check = "Remove Armor/Accessory " + item.name; - } - } - player.IgnoreActionsForDisabledArmor = check; - if (CheckIgnores(player)) - { - player.SetBuff(33, 120); //Weak - player.SetBuff(32, 120); //Slow - player.SetBuff(23, 120); //Cursed - } - else if (!player.Group.HasPermission(Permissions.usebanneditem) && - Itembans.ItemIsBanned(player.TPlayer.inventory[player.TPlayer.selectedItem].name, player)) - { - player.SetBuff(23, 120); //Cursed - } - } - } - SetConsoleTitle(); - } - - private void SetConsoleTitle() - { - Console.Title = string.Format("{0} - {1}/{2} @ {3}:{4} (TerrariaShock v{5})", Config.ServerName, Utils.ActivePlayers(), - Config.MaxSlots, Netplay.serverListenIP, Config.ServerPort, Version); - } - - private void OnConnect(int ply, HandledEventArgs handler) - { - var player = new TSPlayer(ply); - if (Config.EnableDNSHostResolution) - { - player.Group = Users.GetGroupForIPExpensive(player.IP); - } - else - { - player.Group = Users.GetGroupForIP(player.IP); - } - - if (Utils.ActivePlayers() + 1 > Config.MaxSlots + 20) - { - Utils.ForceKick(player, Config.ServerFullNoReservedReason); - handler.Handled = true; - return; - } - - var ipban = Bans.GetBanByIp(player.IP); - Ban ban = null; - if (ipban != null && Config.EnableIPBans) - ban = ipban; - - if (ban != null) - { - Utils.ForceKick(player, string.Format("You are banned: {0}", ban.Reason)); - handler.Handled = true; - return; - } - - if (!FileTools.OnWhitelist(player.IP)) - { - Utils.ForceKick(player, "Not on whitelist."); - handler.Handled = true; - return; - } - - if (Geo != null) - { - var code = Geo.TryGetCountryCode(IPAddress.Parse(player.IP)); - player.Country = code == null ? "N/A" : GeoIPCountry.GetCountryNameByCode(code); - if (code == "A1") - { - if (Config.KickProxyUsers) - { - Utils.ForceKick(player, "Proxies are not allowed"); - handler.Handled = true; - return; - } - } - } - Players[ply] = player; - } - - private void OnJoin(int ply, HandledEventArgs handler) - { - var player = Players[ply]; - if (player == null) - { - handler.Handled = true; - return; - } - - Ban ban = null; - if (Config.EnableBanOnUsernames) - { - var newban = Bans.GetBanByName(player.Name); - if (null != newban) - ban = newban; - } - - if (Config.EnableIPBans && null == ban) - { - ban = Bans.GetBanByIp(player.IP); - } - - if (ban != null) - { - Utils.ForceKick(player, string.Format("You are banned: {0}", ban.Reason)); - handler.Handled = true; - return; - } - } - - private void OnLeave(int ply) - { - - var tsplr = Players[ply]; - Players[ply] = null; - - if (tsplr != null && tsplr.ReceivedInfo) - { - if (!tsplr.SilentKickInProgress) - { - Utils.Broadcast(tsplr.Name + " left", Color.Yellow); - } - Log.Info(string.Format("{0} left.", tsplr.Name)); - - if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan) - { - tsplr.PlayerData.CopyInventory(tsplr); - InventoryDB.InsertPlayerData(tsplr); - } - - if ((Config.RememberLeavePos) &&(!tsplr.LoginHarassed)) - { - RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int) (tsplr.X/16), (int) (tsplr.Y/16)); - } - } - } - - private void OnChat(messageBuffer msg, int ply, string text, HandledEventArgs e) - { - if (e.Handled) - return; - - var tsplr = Players[msg.whoAmI]; - if (tsplr == null) - { - e.Handled = true; - return; - } - - /*if (!Utils.ValidString(text)) - { - e.Handled = true; - return; - }*/ - - if (text.StartsWith("/")) - { - try - { - e.Handled = Commands.HandleCommand(tsplr, text); - } - catch (Exception ex) - { - Log.ConsoleError("Command exception"); - Log.Error(ex.ToString()); - } - } - else if (!tsplr.mute) - { - Utils.Broadcast( - String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, text), - tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); - e.Handled = true; - } - else if (tsplr.mute) - { - tsplr.SendMessage("You are muted!"); - e.Handled = true; - } - } - - /// - /// When a server command is run. - /// - /// - /// - private void ServerHooks_OnCommand(string text, HandledEventArgs e) - { - if (e.Handled) - return; - - // Damn you ThreadStatic and Redigit - if (Main.rand == null) - { - Main.rand = new Random(); - } - if (WorldGen.genRand == null) - { - WorldGen.genRand = new Random(); - } - - if (text.StartsWith("playing") || text.StartsWith("/playing")) - { - int count = 0; - foreach (TSPlayer player in Players) - { - if (player != null && player.Active) - { - count++; - TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, - player.Group.Name, player.UserAccountName)); - } - } - TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count)); - } - else if (text == "autosave") - { - Main.autoSave = Config.AutoSave = !Config.AutoSave; - Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); - } - else if (text.StartsWith("/")) - { - Commands.HandleCommand(TSPlayer.Server, text); - } - else - { - Commands.HandleCommand(TSPlayer.Server, "/" + text); - } - e.Handled = true; - } - - private void OnGetData(GetDataEventArgs e) - { - if (e.Handled) - return; - - PacketTypes type = e.MsgID; - - Debug.WriteLine("Recv: {0:X}: {2} ({1:XX})", e.Msg.whoAmI, (byte) type, type); - - var player = Players[e.Msg.whoAmI]; - if (player == null) - { - e.Handled = true; - return; - } - - if (!player.ConnectionAlive) - { - e.Handled = true; - return; - } - - if (player.RequiresPassword && type != PacketTypes.PasswordSend) - { - e.Handled = true; - return; - } - - if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 && - (int) type != 38 && (int) type != 5 && (int) type != 21) - { - e.Handled = true; - return; - } - - using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length)) - { - try - { - if (GetDataHandlers.HandlerGetData(type, player, data)) - e.Handled = true; - } - catch (Exception ex) - { - Log.Error(ex.ToString()); - } - } - } - - private void OnGreetPlayer(int who, HandledEventArgs e) - { - var player = Players[who]; - if (player == null) - { - e.Handled = true; - return; - } - player.LoginMS= DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - - Utils.ShowFileToUser(player, "motd.txt"); - - if (Config.PvPMode == "always" && !player.TPlayer.hostile) - { - player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", Color.Red); - } - - if (!player.IsLoggedIn) - { - if (Config.ServerSideInventory) - { - player.SendMessage( - player.IgnoreActionsForInventory = "Server Side Inventory is enabled! Please /register or /login to play!", - Color.Red); - player.LoginHarassed = true; - } - else if (Config.RequireLogin) - { - player.SendMessage("Please /register or /login to play!", Color.Red); - player.LoginHarassed = true; - } - } - - if (player.Group.HasPermission(Permissions.causeevents) && Config.InfiniteInvasion) - { - StartInvasion(); - } - - player.LastNetPosition = new Vector2(Main.spawnTileX*16f, Main.spawnTileY*16f); - - if (Config.RememberLeavePos) - { - if (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero){ - var pos = RememberedPos.GetLeavePos(player.Name, player.IP); - - player.Teleport((int) pos.X, (int) pos.Y + 3); - }} - - e.Handled = true; - } - - private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e) - { - if (Config.InfiniteInvasion) - { - IncrementKills(); - if (Main.invasionSize < 10) - { - Main.invasionSize = 20000000; - } - } - } - - private void OnProjectileSetDefaults(SetDefaultsEventArgs e) - { - if (e.Info == 43) - if (Config.DisableTombstones) - e.Object.SetDefaults(0); - if (e.Info == 75) - if (Config.DisableClownBombs) - e.Object.SetDefaults(0); - if (e.Info == 109) - if (Config.DisableSnowBalls) - e.Object.SetDefaults(0); - } - - private void OnNpcSetDefaults(SetDefaultsEventArgs e) - { - if (Itembans.ItemIsBanned(e.Object.name, null)) - { - e.Object.SetDefaults(0); - } - } - - /// - /// Send bytes to client using packetbuffering if available - /// - /// socket to send to - /// bytes to send - /// False on exception - public static bool SendBytes(ServerSock client, byte[] bytes) - { - if (PacketBuffer != null) - { - PacketBuffer.BufferBytes(client, bytes); - return true; - } - - return SendBytesBufferless(client, bytes); - } - - /// - /// Send bytes to a client ignoring the packet buffer - /// - /// socket to send to - /// bytes to send - /// False on exception - public static bool SendBytesBufferless(ServerSock client, byte[] bytes) - { - try - { - if (client.tcpClient.Connected) - client.networkStream.Write(bytes, 0, bytes.Length); - return true; - } - catch (Exception ex) - { - Log.Warn("This is a normal exception"); - Log.Warn(ex.ToString()); - } - return false; - } - - private void NetHooks_SendData(SendDataEventArgs e) - { - if (e.MsgID == PacketTypes.Disconnect) - { - Action senddisconnect = (sock, str) => - { - if (sock == null || !sock.active) - return; - sock.kill = true; - using (var ms = new MemoryStream()) - { - new DisconnectMsg {Reason = str}.PackFull(ms); - SendBytesBufferless(sock, ms.ToArray()); - } - }; - - if (e.remoteClient != -1) - { - senddisconnect(Netplay.serverSock[e.remoteClient], e.text); - } - else - { - for (int i = 0; i < Netplay.serverSock.Length; i++) - { - if (e.ignoreClient != -1 && e.ignoreClient == i) - continue; - - senddisconnect(Netplay.serverSock[i], e.text); - } - } - e.Handled = true; - } - } - - private void OnStartHardMode(HandledEventArgs e) - { - if (Config.DisableHardmode) - e.Handled = true; - } - - /* - * Useful stuff: - * */ - - public static void StartInvasion() - { - Main.invasionType = 1; - if (Config.InfiniteInvasion) - { - Main.invasionSize = 20000000; - } - else - { - Main.invasionSize = 100 + (Config.InvasionMultiplier*Utils.ActivePlayers()); - } - - Main.invasionWarn = 0; - if (new Random().Next(2) == 0) - { - Main.invasionX = 0.0; - } - else - { - Main.invasionX = Main.maxTilesX; - } - } - - private static int KillCount; - - public static void IncrementKills() - { - KillCount++; - Random r = new Random(); - int random = r.Next(5); - if (KillCount%100 == 0) - { - switch (random) - { - case 0: - Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount)); - break; - case 1: - Utils.Broadcast(string.Format("Fatality! {0} goblins killed!", KillCount)); - break; - case 2: - Utils.Broadcast(string.Format("Number of 'noobs' killed to date: {0}", KillCount)); - break; - case 3: - Utils.Broadcast(string.Format("Duke Nukem would be proud. {0} goblins killed.", KillCount)); - break; - case 4: - Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount)); - break; - case 5: - Utils.Broadcast(string.Format("{0} copies of Call of Duty smashed.", KillCount)); - break; - } - } - } - - public static bool CheckProjectilePermission(TSPlayer player, int index, int type) - { - if (type == 43) - { - return true; - } - - if (type == 17 && !player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned("Dirt Rod", player)) - //Dirt Rod Projectile - { - return true; - } - - if ((type == 42 || type == 65 || type == 68) && !player.Group.HasPermission(Permissions.usebanneditem) && - Itembans.ItemIsBanned("Sandgun", player)) //Sandgun Projectiles - { - return true; - } - - Projectile proj = new Projectile(); - proj.SetDefaults(type); - - if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(proj.name, player)) - { - return true; - } - - if (Main.projHostile[type]) - { - //player.SendMessage( proj.name, Color.Yellow); - return true; - } - - return false; - } - - public static bool CheckRangePermission(TSPlayer player, int x, int y, int range = 32) - { - if (Config.RangeChecks && ((Math.Abs(player.TileX - x) > range) || (Math.Abs(player.TileY - y) > range))) - { - return true; - } - return false; - } - - public static bool CheckTilePermission( TSPlayer player, int tileX, int tileY, byte tileType, byte actionType ) - { - if (!player.Group.HasPermission(Permissions.canbuild)) - { - if (TShock.Config.AllowIce && actionType != 1) - { - foreach (Point p in player.IceTiles) - { - if (p.X == tileX && p.Y == tileY && (Main.tile[p.X, p.Y].type == 0 || Main.tile[p.X, p.Y].type == 127)) - { - player.IceTiles.Remove(p); - return false; - } - } - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ - player.SendMessage("You do not have permission to build!", Color.Red); - player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - -} - return true; - } - - if (TShock.Config.AllowIce && actionType == 1 && tileType == 127) - { - player.IceTiles.Add(new Point(tileX, tileY)); - return false; - } - - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ - player.SendMessage("You do not have permission to build!", Color.Red); - player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - -} - return true; - - } - if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) && - Regions.InArea(tileX, tileY)) - { - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){ - player.SendMessage("Region protected from changes.", Color.Red); - player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - -} - return true; - } - if (Config.DisableBuild) - { - if (!player.Group.HasPermission(Permissions.editspawn)) - { - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){ - player.SendMessage("World protected from changes.", Color.Red); - player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - -} - return true; - } - } - if (Config.SpawnProtection) - { - if (!player.Group.HasPermission(Permissions.editspawn)) - { - var flag = CheckSpawn(tileX, tileY); - if (flag) - { - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000){ - player.SendMessage("Spawn protected from changes.", Color.Red); - player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - } - return true; - } - } - } - return false; - } - - public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY) - { - if (!player.Group.HasPermission(Permissions.canbuild)) - { - - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ - player.SendMessage("You do not have permission to build!", Color.Red); - player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - } - return true; - } - - if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) && - Regions.InArea(tileX, tileY)) - { - - - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){ - player.SendMessage("Region protected from changes.", Color.Red); - player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - } - return true; - } - - if (Config.DisableBuild) - { - if (!player.Group.HasPermission(Permissions.editspawn)) - { - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){ - player.SendMessage("World protected from changes.", Color.Red); - player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - } - return true; - } - } - if (Config.SpawnProtection) - { - if (!player.Group.HasPermission(Permissions.editspawn)) - { - var flag = CheckSpawn(tileX, tileY); - if (flag) - { - if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000){ - player.SendMessage("Spawn protected from changes.", Color.Red); - player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - - } - - - return true; - } - } - } - return false; - } - public static bool CheckSpawn(int x, int y) - { - Vector2 tile = new Vector2(x, y); - Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY); - return Distance(spawn, tile) <= Config.SpawnProtectionRadius; - } - - public static float Distance(Vector2 value1, Vector2 value2) - { - float num2 = value1.X - value2.X; - float num = value1.Y - value2.Y; - float num3 = (num2*num2) + (num*num); - return (float) Math.Sqrt(num3); - } - - public static bool HackedHealth(TSPlayer player) - { - return (player.TPlayer.statManaMax > 400) || - (player.TPlayer.statMana > 400) || - (player.TPlayer.statLifeMax > 400) || - (player.TPlayer.statLife > 400); - } - - public static bool HackedInventory(TSPlayer player) - { - bool check = false; - - Item[] inventory = player.TPlayer.inventory; - Item[] armor = player.TPlayer.armor; - for (int i = 0; i < NetItem.maxNetInventory; i++) - { - if (i < 49) - { - Item item = new Item(); - if (inventory[i] != null && inventory[i].netID != 0) - { - item.netDefaults(inventory[i].netID); - item.Prefix(inventory[i].prefix); - item.AffixName(); - if (inventory[i].stack > item.maxStack) - { - check = true; - player.SendMessage( - String.Format("Stack cheat detected. Remove item {0} ({1}) and then rejoin", item.name, inventory[i].stack), - Color.Cyan); - } - } - } - else - { - Item item = new Item(); - if (armor[i - 48] != null && armor[i - 48].netID != 0) - { - item.netDefaults(armor[i - 48].netID); - item.Prefix(armor[i - 48].prefix); - item.AffixName(); - if (armor[i - 48].stack > item.maxStack) - { - check = true; - player.SendMessage( - String.Format("Stack cheat detected. Remove armor {0} ({1}) and then rejoin", item.name, armor[i - 48].stack), - Color.Cyan); - } - } - } - } - - return check; - } - - public static bool CheckInventory(TSPlayer player) - { - PlayerData playerData = player.PlayerData; - bool check = true; - - if (player.TPlayer.statLifeMax > playerData.maxHealth) - { - player.SendMessage("Error: Your max health exceeded (" + playerData.maxHealth + ") which is stored on server", - Color.Cyan); - check = false; - } - - Item[] inventory = player.TPlayer.inventory; - Item[] armor = player.TPlayer.armor; - for (int i = 0; i < NetItem.maxNetInventory; i++) - { - if (i < 49) - { - Item item = new Item(); - Item serverItem = new Item(); - if (inventory[i] != null && inventory[i].netID != 0) - { - if (playerData.inventory[i].netID != inventory[i].netID) - { - item.netDefaults(inventory[i].netID); - item.Prefix(inventory[i].prefix); - item.AffixName(); - player.SendMessage(player.IgnoreActionsForInventory = "Your item (" + item.name + ") needs to be deleted.", - Color.Cyan); - check = false; - } - else if (playerData.inventory[i].prefix != inventory[i].prefix) - { - item.netDefaults(inventory[i].netID); - item.Prefix(inventory[i].prefix); - item.AffixName(); - player.SendMessage(player.IgnoreActionsForInventory = "Your item (" + item.name + ") needs to be deleted.", - Color.Cyan); - check = false; - } - else if (inventory[i].stack > playerData.inventory[i].stack) - { - item.netDefaults(inventory[i].netID); - item.Prefix(inventory[i].prefix); - item.AffixName(); - player.SendMessage( - player.IgnoreActionsForInventory = - "Your item (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" + - playerData.inventory[i].stack + ").", Color.Cyan); - check = false; - } - } - } - else - { - Item item = new Item(); - Item serverItem = new Item(); - if (armor[i - 48] != null && armor[i - 48].netID != 0) - { - if (playerData.inventory[i].netID != armor[i - 48].netID) - { - item.netDefaults(armor[i - 48].netID); - item.Prefix(armor[i - 48].prefix); - item.AffixName(); - player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", - Color.Cyan); - check = false; - } - else if (playerData.inventory[i].prefix != armor[i - 48].prefix) - { - item.netDefaults(armor[i - 48].netID); - item.Prefix(armor[i - 48].prefix); - item.AffixName(); - player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", - Color.Cyan); - check = false; - } - else if (armor[i - 48].stack > playerData.inventory[i].stack) - { - item.netDefaults(armor[i - 48].netID); - item.Prefix(armor[i - 48].prefix); - item.AffixName(); - player.SendMessage( - player.IgnoreActionsForInventory = - "Your armor (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" + - playerData.inventory[i].stack + ").", Color.Cyan); - check = false; - } - } - } - } - - return check; - } - - public static bool CheckIgnores(TSPlayer player) - { - bool check = false; - if (Config.PvPMode == "always" && !player.TPlayer.hostile) - check = true; - if (player.IgnoreActionsForInventory != "none") - check = true; - if (player.IgnoreActionsForCheating != "none") - check = true; - if (player.IgnoreActionsForDisabledArmor != "none") - check = true; - if (player.IgnoreActionsForClearingTrashCan) - check = true; - if (!player.IsLoggedIn && Config.RequireLogin) - check = true; - return check; - } - - public void OnConfigRead(ConfigFile file) - { - NPC.defaultMaxSpawns = file.DefaultMaximumSpawns; - NPC.defaultSpawnRate = file.DefaultSpawnRate; - - Main.autoSave = file.AutoSave; - if (Backups != null) - { - Backups.KeepFor = file.BackupKeepFor; - Backups.Interval = file.BackupInterval; - } - if (!OverridePort) - { - Netplay.serverPort = file.ServerPort; - } - - if (file.MaxSlots > 235) - file.MaxSlots = 235; - Main.maxNetPlayers = file.MaxSlots + 20; - Netplay.password = ""; - Netplay.spamCheck = false; - - RconHandler.Password = file.RconPassword; - RconHandler.ListenPort = file.RconPort; - - Utils.HashAlgo = file.HashAlgorithm; - } - } -} +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Net; +using System.Reflection; +using System.Threading; +using Hooks; +using MaxMind; +using Mono.Data.Sqlite; +using MySql.Data.MySqlClient; +using Rests; +using Terraria; +using TShockAPI.DB; +using TShockAPI.Net; + +namespace TShockAPI +{ + [APIVersion(1, 11)] + public class TShock : TerrariaPlugin + { + public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; + public static readonly string VersionCodename = "Squashing bugs, and adding suggestions"; + + public static string SavePath = "tshock"; + + public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers]; + public static BanManager Bans; + public static WarpManager Warps; + public static RegionManager Regions; + public static BackupManager Backups; + public static GroupManager Groups; + public static UserManager Users; + public static ItemManager Itembans; + public static RemeberedPosManager RememberedPos; + public static InventoryManager InventoryDB; + public static ConfigFile Config { get; set; } + public static IDbConnection DB; + public static bool OverridePort; + public static PacketBufferer PacketBuffer; + public static GeoIPCountry Geo; + public static SecureRest RestApi; + public static RestManager RestManager; + public static Utils Utils = Utils.Instance; + public static StatTracker StatTracker = new StatTracker(); + /// + /// Used for implementing REST Tokens prior to the REST system starting up. + /// + public static Dictionary RESTStartupTokens = new Dictionary(); + + /// + /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. + /// + public static event Action Initialized; + + + public override Version Version + { + get { return VersionNum; } + } + + public override string Name + { + get { return "TShock"; } + } + + public override string Author + { + get { return "The Nyx Team"; } + } + + public override string Description + { + get { return "The administration modification of the future."; } + } + + public TShock(Main game) + : base(game) + { + Config = new ConfigFile(); + Order = 0; + } + + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public override void Initialize() + { + HandleCommandLine(Environment.GetCommandLineArgs()); + + if (!Directory.Exists(SavePath)) + Directory.CreateDirectory(SavePath); + + DateTime now = DateTime.Now; +#if DEBUG + Log.Initialize(Path.Combine(SavePath, now.ToString("yyyyMMddHHmmss")+".log"), LogLevel.All, false); +#else + Log.Initialize(Path.Combine(SavePath, now.ToString("yyyyMMddHHmmss")+".log"), LogLevel.All & ~LogLevel.Debug, false); +#endif + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + + try + { + if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) + { + Log.ConsoleInfo( + "TShock was improperly shut down. Please avoid this in the future, world corruption may result from this."); + File.Delete(Path.Combine(SavePath, "tshock.pid")); + } + File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture)); + + ConfigFile.ConfigRead += OnConfigRead; + FileTools.SetupConfig(); + + HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); + + if (Config.StorageType.ToLower() == "sqlite") + { + string sql = Path.Combine(SavePath, "tshock.sqlite"); + DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql)); + } + else if (Config.StorageType.ToLower() == "mysql") + { + try + { + var hostport = Config.MySqlHost.Split(':'); + DB = new MySqlConnection(); + DB.ConnectionString = + String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", + hostport[0], + hostport.Length > 1 ? hostport[1] : "3306", + Config.MySqlDbName, + Config.MySqlUsername, + Config.MySqlPassword + ); + } + catch (MySqlException ex) + { + Log.Error(ex.ToString()); + throw new Exception("MySql not setup correctly"); + } + } + else + { + throw new Exception("Invalid storage type"); + } + + Backups = new BackupManager(Path.Combine(SavePath, "backups")); + Backups.KeepFor = Config.BackupKeepFor; + Backups.Interval = Config.BackupInterval; + Bans = new BanManager(DB); + Warps = new WarpManager(DB); + Users = new UserManager(DB); + Groups = new GroupManager(DB); + Regions = new RegionManager(DB); + Itembans = new ItemManager(DB); + RememberedPos = new RemeberedPosManager(DB); + InventoryDB = new InventoryManager(DB); + RestApi = new SecureRest(Netplay.serverListenIP, Config.RestApiPort); + RestApi.Verify += RestApi_Verify; + RestApi.Port = Config.RestApiPort; + RestManager = new RestManager(RestApi); + RestManager.RegisterRestfulCommands(); + + var geoippath = Path.Combine(SavePath, "GeoIP.dat"); + if (Config.EnableGeoIP && File.Exists(geoippath)) + Geo = new GeoIPCountry(geoippath); + + Log.ConsoleInfo(string.Format("TerrariaShock Version {0} ({1}) now running.", Version, VersionCodename)); + + GameHooks.PostInitialize += OnPostInit; + GameHooks.Update += OnUpdate; + ServerHooks.Connect += OnConnect; + ServerHooks.Join += OnJoin; + ServerHooks.Leave += OnLeave; + ServerHooks.Chat += OnChat; + ServerHooks.Command += ServerHooks_OnCommand; + NetHooks.GetData += OnGetData; + NetHooks.SendData += NetHooks_SendData; + NetHooks.GreetPlayer += OnGreetPlayer; + NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc; + NpcHooks.SetDefaultsInt += OnNpcSetDefaults; + ProjectileHooks.SetDefaults += OnProjectileSetDefaults; + WorldHooks.StartHardMode += OnStartHardMode; + WorldHooks.SaveWorld += SaveManager.Instance.OnSaveWorld; + + GetDataHandlers.InitGetDataHandler(); + Commands.InitCommands(); + //RconHandler.StartThread(); + + if (Config.RestApiEnabled) + RestApi.Start(); + + if (Config.BufferPackets) + PacketBuffer = new PacketBufferer(); + + Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); + Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled")); + + if (Initialized != null) + Initialized(); + } + catch (Exception ex) + { + Log.Error("Fatal Startup Exception"); + Log.Error(ex.ToString()); + Environment.Exit(1); + } + } + + private RestObject RestApi_Verify(string username, string password) + { + var userAccount = Users.GetUserByName(username); + if (userAccount == null) + { + return new RestObject("401") + {Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."}; + } + + if (Utils.HashPassword(password).ToUpper() != userAccount.Password.ToUpper()) + { + return new RestObject("401") + {Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair."}; + } + + if (!Utils.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") + { + return new RestObject("403") + { + Error = + "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)" + }; + } + + return new RestObject("200") {Response = "Successful login"}; //Maybe return some user info too? + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + // NOTE: order is important here + if (Geo != null) + { + Geo.Dispose(); + } + SaveManager.Instance.Dispose(); + + GameHooks.PostInitialize -= OnPostInit; + GameHooks.Update -= OnUpdate; + ServerHooks.Connect -= OnConnect; + ServerHooks.Join -= OnJoin; + ServerHooks.Leave -= OnLeave; + ServerHooks.Chat -= OnChat; + ServerHooks.Command -= ServerHooks_OnCommand; + NetHooks.GetData -= OnGetData; + NetHooks.SendData -= NetHooks_SendData; + NetHooks.GreetPlayer -= OnGreetPlayer; + NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; + NpcHooks.SetDefaultsInt -= OnNpcSetDefaults; + ProjectileHooks.SetDefaults -= OnProjectileSetDefaults; + WorldHooks.StartHardMode -= OnStartHardMode; + WorldHooks.SaveWorld -= SaveManager.Instance.OnSaveWorld; + + if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) + { + File.Delete(Path.Combine(SavePath, "tshock.pid")); + } + + RestApi.Dispose(); + Log.Dispose(); + } + base.Dispose(disposing); + } + + /// + /// Handles exceptions that we didn't catch or that Red fucked up + /// + /// + /// + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Log.Error(e.ExceptionObject.ToString()); + + if (e.ExceptionObject.ToString().Contains("Terraria.Netplay.ListenForClients") || + e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop")) + { + var sb = new List(); + for (int i = 0; i < Netplay.serverSock.Length; i++) + { + if (Netplay.serverSock[i] == null) + { + sb.Add("Sock[" + i + "]"); + } + else if (Netplay.serverSock[i].tcpClient == null) + { + sb.Add("Tcp[" + i + "]"); + } + } + Log.Error(string.Join(", ", sb)); + } + + if (e.IsTerminating) + { + if (Main.worldPathName != null && Config.SaveWorldOnCrash) + { + Main.worldPathName += ".crash"; + SaveManager.Instance.SaveWorld(); + } + } + } + + private void HandleCommandLine(string[] parms) + { + for (int i = 0; i < parms.Length; i++) + { + if (parms[i].ToLower() == "-configpath") + { + var path = parms[++i]; + if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) + { + SavePath = path; + Log.ConsoleInfo("Config path has been set to " + path); + } + } + if (parms[i].ToLower() == "-worldpath") + { + var path = parms[++i]; + if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) + { + Main.WorldPath = path; + Log.ConsoleInfo("World path has been set to " + path); + } + } + if (parms[i].ToLower() == "-dump") + { + ConfigFile.DumpDescriptions(); + Permissions.DumpDescriptions(); + } + } + } + + public static void HandleCommandLinePostConfigLoad(string[] parms) + { + for (int i = 0; i < parms.Length; i++) + { + switch(parms[i].ToLower()) + { + case "-port": + int port = Convert.ToInt32(parms[++i]); + Netplay.serverPort = port; + Config.ServerPort = port; + OverridePort = true; + Log.ConsoleInfo("Port overridden by startup argument. Set to " + port); + break; + case "-rest-token": + string token = Convert.ToString(parms[++i]); + RESTStartupTokens.Add(token, "null"); + Console.WriteLine("Startup parameter overrode REST token."); + break; + case "-rest-enabled": + Config.RestApiEnabled = Convert.ToBoolean(parms[++i]); + Console.WriteLine("Startup parameter overrode REST enable."); + break; + case "-rest-port": + Config.RestApiPort = Convert.ToInt32(parms[++i]); + Console.WriteLine("Startup parameter overrode REST port."); + break; + case "-maxplayers": + case "-players": + Config.MaxSlots = Convert.ToInt32(parms[++i]); + Console.WriteLine("Startup parameter overrode maximum player slot configuration value."); + break; + } + } + } + + /* + * Hooks: + * + */ + + public static int AuthToken = -1; + + private void OnPostInit() + { + SetConsoleTitle(); + if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt"))) + { + var r = new Random((int) DateTime.Now.ToBinary()); + AuthToken = r.Next(100000, 10000000); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " + AuthToken); + Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); + Console.ForegroundColor = ConsoleColor.Gray; + FileTools.CreateFile(Path.Combine(SavePath, "authcode.txt")); + using (var tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt"))) + { + tw.WriteLine(AuthToken); + } + } + else if (File.Exists(Path.Combine(SavePath, "authcode.txt"))) + { + using (var tr = new StreamReader(Path.Combine(SavePath, "authcode.txt"))) + { + AuthToken = Convert.ToInt32(tr.ReadLine()); + } + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine( + "TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used."); + Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken); + Console.WriteLine("This token will display until disabled by verification. (/auth-verify)"); + Console.ForegroundColor = ConsoleColor.Gray; + } + else + { + AuthToken = 0; + } + Regions.ReloadAllRegions(); + + StatTracker.CheckIn(); + FixChestStacks(); + } + + private void FixChestStacks() + { + foreach (Chest chest in Main.chest) + { + if (chest != null) + { + foreach (Item item in chest.item) + { + if (item != null && item.stack > item.maxStack) + item.stack = item.maxStack; + } + } + } + } + + private DateTime LastCheck = DateTime.UtcNow; + private DateTime LastSave = DateTime.UtcNow; + + private void OnUpdate() + { + UpdateManager.UpdateProcedureCheck(); + StatTracker.CheckIn(); + if (Backups.IsBackupTime) + Backups.Backup(); + //call these every second, not every update + if ((DateTime.UtcNow - LastCheck).TotalSeconds >= 1) + { + OnSecondUpdate(); + LastCheck = DateTime.UtcNow; + } + + if ((DateTime.UtcNow - LastSave).TotalMinutes >= Config.ServerSideInventorySave) + { + foreach (TSPlayer player in Players) + { + // prevent null point exceptions + if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan) + { + + InventoryDB.InsertPlayerData(player); + } + } + LastSave = DateTime.UtcNow; + } + } + + private void OnSecondUpdate() + { + if (Config.ForceTime != "normal") + { + switch (Config.ForceTime) + { + case "day": + TSPlayer.Server.SetTime(true, 27000.0); + break; + case "night": + TSPlayer.Server.SetTime(false, 16200.0); + break; + } + } + int count = 0; + foreach (TSPlayer player in Players) + { + if (player != null && player.Active) + { + count++; + if (player.TilesDestroyed != null) + { + if (player.TileKillThreshold >= Config.TileKillThreshold) + { + player.Disable("Reached TileKill threshold"); + TSPlayer.Server.RevertTiles(player.TilesDestroyed); + player.TilesDestroyed.Clear(); + } + } + if (player.TileKillThreshold > 0) + { + player.TileKillThreshold = 0; + //We don't want to revert the entire map in case of a disable. + player.TilesDestroyed.Clear(); + } + if (player.TilesCreated != null) + { + if (player.TilePlaceThreshold >= Config.TilePlaceThreshold) + { + player.Disable("Reached TilePlace threshold"); + TSPlayer.Server.RevertTiles(player.TilesCreated); + player.TilesCreated.Clear(); + } + } + if (player.TilePlaceThreshold > 0) + { + player.TilePlaceThreshold = 0; + } + if (player.TileLiquidThreshold >= Config.TileLiquidThreshold) + { + player.Disable("Reached TileLiquid threshold"); + } + if (player.TileLiquidThreshold > 0) + { + player.TileLiquidThreshold = 0; + } + if (player.ProjectileThreshold >= Config.ProjectileThreshold) + { + player.Disable("Reached Projectile threshold"); + } + if (player.ProjectileThreshold > 0) + { + player.ProjectileThreshold = 0; + } + if (player.Dead && (DateTime.Now - player.LastDeath).Seconds >= 3 && player.Difficulty != 2) + { + player.Spawn(); + } + string check = "none"; + foreach (Item item in player.TPlayer.inventory) + { + if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && item.stack > item.maxStack && + item.type != 0) + { + check = "Remove Item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack; + } + } + player.IgnoreActionsForCheating = check; + check = "none"; + foreach (Item item in player.TPlayer.armor) + { + if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(item.name, player)) + { + player.SetBuff(30, 120); //Bleeding + player.SetBuff(36, 120); //Broken Armor + check = "Remove Armor/Accessory " + item.name; + } + } + player.IgnoreActionsForDisabledArmor = check; + if (CheckIgnores(player)) + { + player.SetBuff(33, 120); //Weak + player.SetBuff(32, 120); //Slow + player.SetBuff(23, 120); //Cursed + } + else if (!player.Group.HasPermission(Permissions.usebanneditem) && + Itembans.ItemIsBanned(player.TPlayer.inventory[player.TPlayer.selectedItem].name, player)) + { + player.SetBuff(23, 120); //Cursed + } + } + } + SetConsoleTitle(); + } + + private void SetConsoleTitle() + { + Console.Title = string.Format("{0} - {1}/{2} @ {3}:{4} (TerrariaShock v{5})", Config.ServerName, Utils.ActivePlayers(), + Config.MaxSlots, Netplay.serverListenIP, Config.ServerPort, Version); + } + + private void OnConnect(int ply, HandledEventArgs handler) + { + var player = new TSPlayer(ply); + if (Config.EnableDNSHostResolution) + { + player.Group = Users.GetGroupForIPExpensive(player.IP); + } + else + { + player.Group = Users.GetGroupForIP(player.IP); + } + + if (Utils.ActivePlayers() + 1 > Config.MaxSlots + 20) + { + Utils.ForceKick(player, Config.ServerFullNoReservedReason); + handler.Handled = true; + return; + } + + var ipban = Bans.GetBanByIp(player.IP); + Ban ban = null; + if (ipban != null && Config.EnableIPBans) + ban = ipban; + + if (ban != null) + { + Utils.ForceKick(player, string.Format("You are banned: {0}", ban.Reason)); + handler.Handled = true; + return; + } + + if (!FileTools.OnWhitelist(player.IP)) + { + Utils.ForceKick(player, "Not on whitelist."); + handler.Handled = true; + return; + } + + if (Geo != null) + { + var code = Geo.TryGetCountryCode(IPAddress.Parse(player.IP)); + player.Country = code == null ? "N/A" : GeoIPCountry.GetCountryNameByCode(code); + if (code == "A1") + { + if (Config.KickProxyUsers) + { + Utils.ForceKick(player, "Proxies are not allowed"); + handler.Handled = true; + return; + } + } + } + Players[ply] = player; + } + + private void OnJoin(int ply, HandledEventArgs handler) + { + var player = Players[ply]; + if (player == null) + { + handler.Handled = true; + return; + } + + Ban ban = null; + if (Config.EnableBanOnUsernames) + { + var newban = Bans.GetBanByName(player.Name); + if (null != newban) + ban = newban; + } + + if (Config.EnableIPBans && null == ban) + { + ban = Bans.GetBanByIp(player.IP); + } + + if (ban != null) + { + Utils.ForceKick(player, string.Format("You are banned: {0}", ban.Reason)); + handler.Handled = true; + return; + } + } + + private void OnLeave(int ply) + { + + var tsplr = Players[ply]; + Players[ply] = null; + + if (tsplr != null && tsplr.ReceivedInfo) + { + if (!tsplr.SilentKickInProgress) + { + Utils.Broadcast(tsplr.Name + " left", Color.Yellow); + } + Log.Info(string.Format("{0} left.", tsplr.Name)); + + if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan) + { + tsplr.PlayerData.CopyInventory(tsplr); + InventoryDB.InsertPlayerData(tsplr); + } + + if ((Config.RememberLeavePos) &&(!tsplr.LoginHarassed)) + { + RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int) (tsplr.X/16), (int) (tsplr.Y/16)); + } + } + } + + private void OnChat(messageBuffer msg, int ply, string text, HandledEventArgs e) + { + if (e.Handled) + return; + + var tsplr = Players[msg.whoAmI]; + if (tsplr == null) + { + e.Handled = true; + return; + } + + /*if (!Utils.ValidString(text)) + { + e.Handled = true; + return; + }*/ + + if (text.StartsWith("/")) + { + try + { + e.Handled = Commands.HandleCommand(tsplr, text); + } + catch (Exception ex) + { + Log.ConsoleError("Command exception"); + Log.Error(ex.ToString()); + } + } + else if (!tsplr.mute) + { + Utils.Broadcast( + String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, text), + tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); + e.Handled = true; + } + else if (tsplr.mute) + { + tsplr.SendMessage("You are muted!"); + e.Handled = true; + } + } + + /// + /// When a server command is run. + /// + /// + /// + private void ServerHooks_OnCommand(string text, HandledEventArgs e) + { + if (e.Handled) + return; + + // Damn you ThreadStatic and Redigit + if (Main.rand == null) + { + Main.rand = new Random(); + } + if (WorldGen.genRand == null) + { + WorldGen.genRand = new Random(); + } + + if (text.StartsWith("playing") || text.StartsWith("/playing")) + { + int count = 0; + foreach (TSPlayer player in Players) + { + if (player != null && player.Active) + { + count++; + TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP, + player.Group.Name, player.UserAccountName)); + } + } + TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count)); + } + else if (text == "autosave") + { + Main.autoSave = Config.AutoSave = !Config.AutoSave; + Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); + } + else if (text.StartsWith("/")) + { + Commands.HandleCommand(TSPlayer.Server, text); + } + else + { + Commands.HandleCommand(TSPlayer.Server, "/" + text); + } + e.Handled = true; + } + + private void OnGetData(GetDataEventArgs e) + { + if (e.Handled) + return; + + PacketTypes type = e.MsgID; + + Debug.WriteLine("Recv: {0:X}: {2} ({1:XX})", e.Msg.whoAmI, (byte) type, type); + + var player = Players[e.Msg.whoAmI]; + if (player == null) + { + e.Handled = true; + return; + } + + if (!player.ConnectionAlive) + { + e.Handled = true; + return; + } + + if (player.RequiresPassword && type != PacketTypes.PasswordSend) + { + e.Handled = true; + return; + } + + if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 && + (int) type != 38 && (int) type != 5 && (int) type != 21) + { + e.Handled = true; + return; + } + + using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length)) + { + try + { + if (GetDataHandlers.HandlerGetData(type, player, data)) + e.Handled = true; + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + } + } + + private void OnGreetPlayer(int who, HandledEventArgs e) + { + var player = Players[who]; + if (player == null) + { + e.Handled = true; + return; + } + player.LoginMS= DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + + Utils.ShowFileToUser(player, "motd.txt"); + + if (Config.PvPMode == "always" && !player.TPlayer.hostile) + { + player.SendMessage("PvP is forced! Enable PvP else you can't move or do anything!", Color.Red); + } + + if (!player.IsLoggedIn) + { + if (Config.ServerSideInventory) + { + player.SendMessage( + player.IgnoreActionsForInventory = "Server Side Inventory is enabled! Please /register or /login to play!", + Color.Red); + player.LoginHarassed = true; + } + else if (Config.RequireLogin) + { + player.SendMessage("Please /register or /login to play!", Color.Red); + player.LoginHarassed = true; + } + } + + if (player.Group.HasPermission(Permissions.causeevents) && Config.InfiniteInvasion) + { + StartInvasion(); + } + + player.LastNetPosition = new Vector2(Main.spawnTileX*16f, Main.spawnTileY*16f); + + if (Config.RememberLeavePos) + { + if (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero){ + var pos = RememberedPos.GetLeavePos(player.Name, player.IP); + + player.Teleport((int) pos.X, (int) pos.Y + 3); + }} + + e.Handled = true; + } + + private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e) + { + if (Config.InfiniteInvasion) + { + IncrementKills(); + if (Main.invasionSize < 10) + { + Main.invasionSize = 20000000; + } + } + } + + private void OnProjectileSetDefaults(SetDefaultsEventArgs e) + { + if (e.Info == 43) + if (Config.DisableTombstones) + e.Object.SetDefaults(0); + if (e.Info == 75) + if (Config.DisableClownBombs) + e.Object.SetDefaults(0); + if (e.Info == 109) + if (Config.DisableSnowBalls) + e.Object.SetDefaults(0); + } + + private void OnNpcSetDefaults(SetDefaultsEventArgs e) + { + if (Itembans.ItemIsBanned(e.Object.name, null)) + { + e.Object.SetDefaults(0); + } + } + + /// + /// Send bytes to client using packetbuffering if available + /// + /// socket to send to + /// bytes to send + /// False on exception + public static bool SendBytes(ServerSock client, byte[] bytes) + { + if (PacketBuffer != null) + { + PacketBuffer.BufferBytes(client, bytes); + return true; + } + + return SendBytesBufferless(client, bytes); + } + + /// + /// Send bytes to a client ignoring the packet buffer + /// + /// socket to send to + /// bytes to send + /// False on exception + public static bool SendBytesBufferless(ServerSock client, byte[] bytes) + { + try + { + if (client.tcpClient.Connected) + client.networkStream.Write(bytes, 0, bytes.Length); + return true; + } + catch (Exception ex) + { + Log.Warn("This is a normal exception"); + Log.Warn(ex.ToString()); + } + return false; + } + + private void NetHooks_SendData(SendDataEventArgs e) + { + if (e.MsgID == PacketTypes.Disconnect) + { + Action senddisconnect = (sock, str) => + { + if (sock == null || !sock.active) + return; + sock.kill = true; + using (var ms = new MemoryStream()) + { + new DisconnectMsg {Reason = str}.PackFull(ms); + SendBytesBufferless(sock, ms.ToArray()); + } + }; + + if (e.remoteClient != -1) + { + senddisconnect(Netplay.serverSock[e.remoteClient], e.text); + } + else + { + for (int i = 0; i < Netplay.serverSock.Length; i++) + { + if (e.ignoreClient != -1 && e.ignoreClient == i) + continue; + + senddisconnect(Netplay.serverSock[i], e.text); + } + } + e.Handled = true; + } + } + + private void OnStartHardMode(HandledEventArgs e) + { + if (Config.DisableHardmode) + e.Handled = true; + } + + /* + * Useful stuff: + * */ + + public static void StartInvasion() + { + Main.invasionType = 1; + if (Config.InfiniteInvasion) + { + Main.invasionSize = 20000000; + } + else + { + Main.invasionSize = 100 + (Config.InvasionMultiplier*Utils.ActivePlayers()); + } + + Main.invasionWarn = 0; + if (new Random().Next(2) == 0) + { + Main.invasionX = 0.0; + } + else + { + Main.invasionX = Main.maxTilesX; + } + } + + private static int KillCount; + + public static void IncrementKills() + { + KillCount++; + Random r = new Random(); + int random = r.Next(5); + if (KillCount%100 == 0) + { + switch (random) + { + case 0: + Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount)); + break; + case 1: + Utils.Broadcast(string.Format("Fatality! {0} goblins killed!", KillCount)); + break; + case 2: + Utils.Broadcast(string.Format("Number of 'noobs' killed to date: {0}", KillCount)); + break; + case 3: + Utils.Broadcast(string.Format("Duke Nukem would be proud. {0} goblins killed.", KillCount)); + break; + case 4: + Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount)); + break; + case 5: + Utils.Broadcast(string.Format("{0} copies of Call of Duty smashed.", KillCount)); + break; + } + } + } + + public static bool CheckProjectilePermission(TSPlayer player, int index, int type) + { + if (type == 43) + { + return true; + } + + if (type == 17 && !player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned("Dirt Rod", player)) + //Dirt Rod Projectile + { + return true; + } + + if ((type == 42 || type == 65 || type == 68) && !player.Group.HasPermission(Permissions.usebanneditem) && + Itembans.ItemIsBanned("Sandgun", player)) //Sandgun Projectiles + { + return true; + } + + Projectile proj = new Projectile(); + proj.SetDefaults(type); + + if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(proj.name, player)) + { + return true; + } + + if (Main.projHostile[type]) + { + //player.SendMessage( proj.name, Color.Yellow); + return true; + } + + return false; + } + + public static bool CheckRangePermission(TSPlayer player, int x, int y, int range = 32) + { + if (Config.RangeChecks && ((Math.Abs(player.TileX - x) > range) || (Math.Abs(player.TileY - y) > range))) + { + return true; + } + return false; + } + + public static bool CheckTilePermission( TSPlayer player, int tileX, int tileY, byte tileType, byte actionType ) + { + if (!player.Group.HasPermission(Permissions.canbuild)) + { + if (TShock.Config.AllowIce && actionType != 1) + { + foreach (Point p in player.IceTiles) + { + if (p.X == tileX && p.Y == tileY && (Main.tile[p.X, p.Y].type == 0 || Main.tile[p.X, p.Y].type == 127)) + { + player.IceTiles.Remove(p); + return false; + } + } + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ + player.SendMessage("You do not have permission to build!", Color.Red); + player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + +} + return true; + } + + if (TShock.Config.AllowIce && actionType == 1 && tileType == 127) + { + player.IceTiles.Add(new Point(tileX, tileY)); + return false; + } + + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ + player.SendMessage("You do not have permission to build!", Color.Red); + player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + +} + return true; + + } + if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) && + Regions.InArea(tileX, tileY)) + { + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){ + player.SendMessage("Region protected from changes.", Color.Red); + player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + +} + return true; + } + if (Config.DisableBuild) + { + if (!player.Group.HasPermission(Permissions.editspawn)) + { + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){ + player.SendMessage("World protected from changes.", Color.Red); + player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + +} + return true; + } + } + if (Config.SpawnProtection) + { + if (!player.Group.HasPermission(Permissions.editspawn)) + { + var flag = CheckSpawn(tileX, tileY); + if (flag) + { + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000){ + player.SendMessage("Spawn protected from changes.", Color.Red); + player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + } + return true; + } + } + } + return false; + } + + public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY) + { + if (!player.Group.HasPermission(Permissions.canbuild)) + { + + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000){ + player.SendMessage("You do not have permission to build!", Color.Red); + player.BPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + } + return true; + } + + if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) && + Regions.InArea(tileX, tileY)) + { + + + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000){ + player.SendMessage("Region protected from changes.", Color.Red); + player.RPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + } + return true; + } + + if (Config.DisableBuild) + { + if (!player.Group.HasPermission(Permissions.editspawn)) + { + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){ + player.SendMessage("World protected from changes.", Color.Red); + player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + } + return true; + } + } + if (Config.SpawnProtection) + { + if (!player.Group.HasPermission(Permissions.editspawn)) + { + var flag = CheckSpawn(tileX, tileY); + if (flag) + { + if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000){ + player.SendMessage("Spawn protected from changes.", Color.Red); + player.SPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + + } + + + return true; + } + } + } + return false; + } + public static bool CheckSpawn(int x, int y) + { + Vector2 tile = new Vector2(x, y); + Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY); + return Distance(spawn, tile) <= Config.SpawnProtectionRadius; + } + + public static float Distance(Vector2 value1, Vector2 value2) + { + float num2 = value1.X - value2.X; + float num = value1.Y - value2.Y; + float num3 = (num2*num2) + (num*num); + return (float) Math.Sqrt(num3); + } + + public static bool HackedHealth(TSPlayer player) + { + return (player.TPlayer.statManaMax > 400) || + (player.TPlayer.statMana > 400) || + (player.TPlayer.statLifeMax > 400) || + (player.TPlayer.statLife > 400); + } + + public static bool HackedInventory(TSPlayer player) + { + bool check = false; + + Item[] inventory = player.TPlayer.inventory; + Item[] armor = player.TPlayer.armor; + for (int i = 0; i < NetItem.maxNetInventory; i++) + { + if (i < 49) + { + Item item = new Item(); + if (inventory[i] != null && inventory[i].netID != 0) + { + item.netDefaults(inventory[i].netID); + item.Prefix(inventory[i].prefix); + item.AffixName(); + if (inventory[i].stack > item.maxStack) + { + check = true; + player.SendMessage( + String.Format("Stack cheat detected. Remove item {0} ({1}) and then rejoin", item.name, inventory[i].stack), + Color.Cyan); + } + } + } + else + { + Item item = new Item(); + if (armor[i - 48] != null && armor[i - 48].netID != 0) + { + item.netDefaults(armor[i - 48].netID); + item.Prefix(armor[i - 48].prefix); + item.AffixName(); + if (armor[i - 48].stack > item.maxStack) + { + check = true; + player.SendMessage( + String.Format("Stack cheat detected. Remove armor {0} ({1}) and then rejoin", item.name, armor[i - 48].stack), + Color.Cyan); + } + } + } + } + + return check; + } + + public static bool CheckInventory(TSPlayer player) + { + PlayerData playerData = player.PlayerData; + bool check = true; + + if (player.TPlayer.statLifeMax > playerData.maxHealth) + { + player.SendMessage("Error: Your max health exceeded (" + playerData.maxHealth + ") which is stored on server", + Color.Cyan); + check = false; + } + + Item[] inventory = player.TPlayer.inventory; + Item[] armor = player.TPlayer.armor; + for (int i = 0; i < NetItem.maxNetInventory; i++) + { + if (i < 49) + { + Item item = new Item(); + Item serverItem = new Item(); + if (inventory[i] != null && inventory[i].netID != 0) + { + if (playerData.inventory[i].netID != inventory[i].netID) + { + item.netDefaults(inventory[i].netID); + item.Prefix(inventory[i].prefix); + item.AffixName(); + player.SendMessage(player.IgnoreActionsForInventory = "Your item (" + item.name + ") needs to be deleted.", + Color.Cyan); + check = false; + } + else if (playerData.inventory[i].prefix != inventory[i].prefix) + { + item.netDefaults(inventory[i].netID); + item.Prefix(inventory[i].prefix); + item.AffixName(); + player.SendMessage(player.IgnoreActionsForInventory = "Your item (" + item.name + ") needs to be deleted.", + Color.Cyan); + check = false; + } + else if (inventory[i].stack > playerData.inventory[i].stack) + { + item.netDefaults(inventory[i].netID); + item.Prefix(inventory[i].prefix); + item.AffixName(); + player.SendMessage( + player.IgnoreActionsForInventory = + "Your item (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" + + playerData.inventory[i].stack + ").", Color.Cyan); + check = false; + } + } + } + else + { + Item item = new Item(); + Item serverItem = new Item(); + if (armor[i - 48] != null && armor[i - 48].netID != 0) + { + if (playerData.inventory[i].netID != armor[i - 48].netID) + { + item.netDefaults(armor[i - 48].netID); + item.Prefix(armor[i - 48].prefix); + item.AffixName(); + player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", + Color.Cyan); + check = false; + } + else if (playerData.inventory[i].prefix != armor[i - 48].prefix) + { + item.netDefaults(armor[i - 48].netID); + item.Prefix(armor[i - 48].prefix); + item.AffixName(); + player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", + Color.Cyan); + check = false; + } + else if (armor[i - 48].stack > playerData.inventory[i].stack) + { + item.netDefaults(armor[i - 48].netID); + item.Prefix(armor[i - 48].prefix); + item.AffixName(); + player.SendMessage( + player.IgnoreActionsForInventory = + "Your armor (" + item.name + ") (" + inventory[i].stack + ") needs to have it's stack decreased to (" + + playerData.inventory[i].stack + ").", Color.Cyan); + check = false; + } + } + } + } + + return check; + } + + public static bool CheckIgnores(TSPlayer player) + { + bool check = false; + if (Config.PvPMode == "always" && !player.TPlayer.hostile) + check = true; + if (player.IgnoreActionsForInventory != "none") + check = true; + if (player.IgnoreActionsForCheating != "none") + check = true; + if (player.IgnoreActionsForDisabledArmor != "none") + check = true; + if (player.IgnoreActionsForClearingTrashCan) + check = true; + if (!player.IsLoggedIn && Config.RequireLogin) + check = true; + return check; + } + + public void OnConfigRead(ConfigFile file) + { + NPC.defaultMaxSpawns = file.DefaultMaximumSpawns; + NPC.defaultSpawnRate = file.DefaultSpawnRate; + + Main.autoSave = file.AutoSave; + if (Backups != null) + { + Backups.KeepFor = file.BackupKeepFor; + Backups.Interval = file.BackupInterval; + } + if (!OverridePort) + { + Netplay.serverPort = file.ServerPort; + } + + if (file.MaxSlots > 235) + file.MaxSlots = 235; + Main.maxNetPlayers = file.MaxSlots + 20; + Netplay.password = ""; + Netplay.spamCheck = false; + + RconHandler.Password = file.RconPassword; + RconHandler.ListenPort = file.RconPort; + + Utils.HashAlgo = file.HashAlgorithm; + } + } +} diff --git a/TShockAPI/UpdateManager.cs b/TShockAPI/UpdateManager.cs index dcc28f20b..cf0b375b9 100644 --- a/TShockAPI/UpdateManager.cs +++ b/TShockAPI/UpdateManager.cs @@ -1,102 +1,102 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading; -using Newtonsoft.Json; - -namespace TShockAPI -{ - internal class UpdateManager - { - private static string updateUrl = "http://shankshock.com/tshock-update.json"; - public static DateTime lastcheck = DateTime.MinValue; - - /// - /// Check once every X minutes. - /// - private static readonly int CheckXMinutes = 30; - - public static void UpdateProcedureCheck() - { - if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes) - { - ThreadPool.QueueUserWorkItem(CheckUpdate); - lastcheck = DateTime.Now; - } - } - - public static void CheckUpdate(object o) - { - var updates = ServerIsOutOfDate(); - if (updates != null) - { - NotifyAdministrators(updates); - } - } - - /// - /// Checks to see if the server is out of date. - /// - /// - private static Dictionary ServerIsOutOfDate() - { - using (var client = new WebClient()) - { - client.Headers.Add("user-agent", - "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)"); - try - { - string updatejson = client.DownloadString(updateUrl); - var update = JsonConvert.DeserializeObject>(updatejson); - var version = new Version(update["version"]); - if (TShock.VersionNum.CompareTo(version) < 0) - return update; - } - catch (Exception e) - { - Log.Error(e.ToString()); - } - return null; - } - } - - private static void NotifyAdministrators(Dictionary update) - { - var changes = update["changes"].Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries); - NotifyAdministrator(TSPlayer.Server, changes); - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active && player.Group.HasPermission(Permissions.maintenance)) - { - NotifyAdministrator(player, changes); - } - } - } - - private static void NotifyAdministrator(TSPlayer player, string[] changes) - { - player.SendMessage("The server is out of date.", Color.Red); - for (int j = 0; j < changes.Length; j++) - { - player.SendMessage(changes[j], Color.Red); - } - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using Newtonsoft.Json; + +namespace TShockAPI +{ + internal class UpdateManager + { + private static string updateUrl = "http://shankshock.com/tshock-update.json"; + public static DateTime lastcheck = DateTime.MinValue; + + /// + /// Check once every X minutes. + /// + private static readonly int CheckXMinutes = 30; + + public static void UpdateProcedureCheck() + { + if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes) + { + ThreadPool.QueueUserWorkItem(CheckUpdate); + lastcheck = DateTime.Now; + } + } + + public static void CheckUpdate(object o) + { + var updates = ServerIsOutOfDate(); + if (updates != null) + { + NotifyAdministrators(updates); + } + } + + /// + /// Checks to see if the server is out of date. + /// + /// + private static Dictionary ServerIsOutOfDate() + { + using (var client = new WebClient()) + { + client.Headers.Add("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)"); + try + { + string updatejson = client.DownloadString(updateUrl); + var update = JsonConvert.DeserializeObject>(updatejson); + var version = new Version(update["version"]); + if (TShock.VersionNum.CompareTo(version) < 0) + return update; + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + return null; + } + } + + private static void NotifyAdministrators(Dictionary update) + { + var changes = update["changes"].Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries); + NotifyAdministrator(TSPlayer.Server, changes); + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active && player.Group.HasPermission(Permissions.maintenance)) + { + NotifyAdministrator(player, changes); + } + } + } + + private static void NotifyAdministrator(TSPlayer player, string[] changes) + { + player.SendMessage("The server is out of date.", Color.Red); + for (int j = 0; j < changes.Length; j++) + { + player.SendMessage(changes[j], Color.Red); + } + } + } } \ No newline at end of file diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index d5caa544c..2d2975aed 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -1,783 +1,783 @@ -/* -TShock, a server mod for Terraria -Copyright (C) 2011 The TShock Team - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography; -using System.Text; -using Terraria; - -namespace TShockAPI -{ - public class Utils - { - private readonly static int firstItemPrefix = 1; - private readonly static int lastItemPrefix = 83; - // Utils is a Singleton - private static readonly Utils instance = new Utils(); - private Utils() {} - public static Utils Instance { get { return instance; } } - - public Random Random = new Random(); - //private static List groups = new List(); - - /// - /// Provides the real IP address from a RemoteEndPoint string that contains a port and an IP - /// - /// A string IPv4 address in IP:PORT form. - /// A string IPv4 address. - public string GetRealIP(string mess) - { - return mess.Split(':')[0]; - } - - /// - /// Used for some places where a list of players might be used. - /// - /// String of players seperated by commas. - public string GetPlayers() - { - var sb = new StringBuilder(); - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - if (sb.Length != 0) - { - sb.Append(", "); - } - sb.Append(player.Name); - } - } - return sb.ToString(); - } - - /// - /// Used for some places where a list of players might be used. - /// - /// String of players and their id seperated by commas. - public string GetPlayersWithIds() - { - var sb = new StringBuilder(); - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - if (sb.Length != 0) - { - sb.Append(", "); - } - sb.Append(player.Name); - string id = "( " + Convert.ToString(TShock.Users.GetUserID(player.UserAccountName)) + " )"; - sb.Append(id); - } - } - return sb.ToString(); - } - - /// - /// Finds a player and gets IP as string - /// - /// Player name - public string GetPlayerIP(string playername) - { - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - if (playername.ToLower() == player.Name.ToLower()) - { - return player.IP; - } - } - } - return null; - } - - /// - /// It's a clamp function - /// - /// - /// Value to clamp - /// Maximum bounds of the clamp - /// Minimum bounds of the clamp - /// - public T Clamp(T value, T max, T min) - where T : IComparable - { - T result = value; - if (value.CompareTo(max) > 0) - result = max; - if (value.CompareTo(min) < 0) - result = min; - return result; - } - - /// - /// Saves the map data - /// - public void SaveWorld() - { - SaveManager.Instance.SaveWorld(); - } - - /// - /// Broadcasts a message to all players - /// - /// string message - public void Broadcast(string msg) - { - Broadcast(msg, Color.Green); - } - - public void Broadcast(string msg, byte red, byte green, byte blue) - { - TSPlayer.All.SendMessage(msg, red, green, blue); - TSPlayer.Server.SendMessage(msg, red, green, blue); - Log.Info(string.Format("Broadcast: {0}", msg)); - } - - public void Broadcast(string msg, Color color) - { - Broadcast(msg, color.R, color.G, color.B); - } - - /// - /// Sends message to all users with 'logs' permission. - /// - /// Message to send - /// Color of the message - public void SendLogs(string log, Color color) - { - Log.Info(log); - TSPlayer.Server.SendMessage(log, color); - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active && player.Group.HasPermission(Permissions.logs) && player.DisplayLogs && - TShock.Config.DisableSpewLogs == false) - player.SendMessage(log, color); - } - } - - /// - /// The number of active players on the server. - /// - /// int playerCount - public int ActivePlayers() - { - return Main.player.Where(p => null != p && p.active).Count(); - } - - /// - /// Finds a player ID based on name - /// - /// Player name - /// - public List FindPlayer(string ply) - { - var found = new List(); - // Avoid errors caused by null search - if (null == ply) - return found; - ply = ply.ToLower(); - foreach (TSPlayer player in TShock.Players) - { - if (player == null) - continue; - - string name = player.Name.ToLower(); - if (name.Equals(ply)) - return new List {player}; - if (name.Contains(ply)) - found.Add(player); - } - return found; - } - - /// - /// Gets a random clear tile in range - /// - /// Bound X - /// Bound Y - /// Range on the X axis - /// Range on the Y axis - /// X location - /// Y location - public void GetRandomClearTileWithInRange(int startTileX, int startTileY, int tileXRange, int tileYRange, - out int tileX, out int tileY) - { - int j = 0; - do - { - if (j == 100) - { - tileX = startTileX; - tileY = startTileY; - break; - } - - tileX = startTileX + Random.Next(tileXRange*-1, tileXRange); - tileY = startTileY + Random.Next(tileYRange*-1, tileYRange); - j++; - } while (TileValid(tileX, tileY) && !TileClear(tileX, tileY)); - } - - /// - /// Determines if a tile is valid - /// - /// Location X - /// Location Y - /// If the tile is valid - private bool TileValid(int tileX, int tileY) - { - return tileX >= 0 && tileX <= Main.maxTilesX && tileY >= 0 && tileY <= Main.maxTilesY; - } - - /// - /// Clears a tile - /// - /// Location X - /// Location Y - /// The state of the tile - private bool TileClear(int tileX, int tileY) - { - return !Main.tile[tileX, tileY].active; - } - - /// - /// Gets a list of items by ID or name - /// - /// Item ID or name - /// List of Items - public List GetItemByIdOrName(string idOrName) - { - int type = -1; - if (int.TryParse(idOrName, out type)) - { - return new List {GetItemById(type)}; - } - return GetItemByName(idOrName); - } - - /// - /// Gets an item by ID - /// - /// ID - /// Item - public Item GetItemById(int id) - { - Item item = new Item(); - item.netDefaults(id); - return item; - } - - /// - /// Gets items by name - /// - /// name - /// List of Items - public List GetItemByName(string name) - { - //Method #1 - must be exact match, allows support for different pickaxes/hammers/swords etc - for (int i = 1; i < Main.maxItemTypes; i++) - { - Item item = new Item(); - item.SetDefaults(name); - if (item.name == name) - return new List {item}; - } - //Method #2 - allows impartial matching - var found = new List(); - for (int i = -24; i < Main.maxItemTypes; i++) - { - try - { - Item item = new Item(); - item.netDefaults(i); - if (item.name.ToLower() == name.ToLower()) - return new List {item}; - if (item.name.ToLower().StartsWith(name.ToLower())) - found.Add(item); - } - catch - { - } - } - return found; - } - - /// - /// Gets an NPC by ID or Name - /// - /// - /// List of NPCs - public List GetNPCByIdOrName(string idOrName) - { - int type = -1; - if (int.TryParse(idOrName, out type)) - { - return new List {GetNPCById(type)}; - } - return GetNPCByName(idOrName); - } - - /// - /// Gets an NPC by ID - /// - /// ID - /// NPC - public NPC GetNPCById(int id) - { - NPC npc = new NPC(); - npc.netDefaults(id); - return npc; - } - - /// - /// Gets a NPC by name - /// - /// Name - /// List of matching NPCs - public List GetNPCByName(string name) - { - //Method #1 - must be exact match, allows support for different coloured slimes - for (int i = -17; i < Main.maxNPCTypes; i++) - { - NPC npc = new NPC(); - npc.SetDefaults(name); - if (npc.name == name) - return new List {npc}; - } - //Method #2 - allows impartial matching - var found = new List(); - for (int i = 1; i < Main.maxNPCTypes; i++) - { - NPC npc = new NPC(); - npc.netDefaults(i); - if (npc.name.ToLower() == name.ToLower()) - return new List {npc}; - if (npc.name.ToLower().StartsWith(name.ToLower())) - found.Add(npc); - } - return found; - } - - /// - /// Gets a buff name by id - /// - /// ID - /// name - public string GetBuffName(int id) - { - return (id > 0 && id < Main.maxBuffs) ? Main.buffName[id] : "null"; - } - - /// - /// Gets the description of a buff - /// - /// ID - /// description - public string GetBuffDescription(int id) - { - return (id > 0 && id < Main.maxBuffs) ? Main.buffTip[id] : "null"; - } - - /// - /// Gets a list of buffs by name - /// - /// name - /// Matching list of buff ids - public List GetBuffByName(string name) - { - for (int i = 1; i < Main.maxBuffs; i++) - { - if (Main.buffName[i].ToLower() == name) - return new List {i}; - } - var found = new List(); - for (int i = 1; i < Main.maxBuffs; i++) - { - if (Main.buffName[i].ToLower().StartsWith(name.ToLower())) - found.Add(i); - } - return found; - } - - /// - /// Gets a prefix based on its id - /// - /// ID - /// Prefix name - public string GetPrefixById(int id) - { - var item = new Item(); - item.SetDefaults(0); - item.prefix = (byte) id; - item.AffixName(); - return item.name.Trim(); - } - - /// - /// Gets a list of prefixes by name - /// - /// Name - /// List of prefix IDs - public List GetPrefixByName(string name) - { - Item item = new Item(); - item.SetDefaults(0); - string lowerName = name.ToLower(); - var found = new List(); - for (int i = firstItemPrefix; i <= lastItemPrefix; i++) - { - try - { - item.prefix = (byte)i; - string trimmed = item.AffixName().Trim(); - if (trimmed == name) - { - // Exact match - found.Add(i); - return found; - } - else - { - string trimmedLower = trimmed.ToLower(); - if (trimmedLower == lowerName) - { - // Exact match (caseinsensitive) - found.Add(i); - return found; - } - else if (trimmedLower.StartsWith(lowerName)) // Partial match - found.Add(i); - } - } - catch - { - } - } - return found; - } - - /// - /// Gets a prefix by ID or name - /// - /// ID or name - /// List of prefix IDs - public List GetPrefixByIdOrName(string idOrName) - { - int type = -1; - if (int.TryParse(idOrName, out type) && type >= firstItemPrefix && type <= lastItemPrefix) - { - return new List {type}; - } - return GetPrefixByName(idOrName); - } - - /// - /// Kicks all player from the server without checking for immunetokick permission. - /// - /// int player - /// string reason - public void ForceKickAll(string reason) - { - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - ForceKick(player, reason); - } - } - } - - /// - /// Stops the server after kicking all players with a reason message, and optionally saving the world - /// - /// bool perform a world save before stop (default: true) - /// string reason (default: "Server shutting down!") - public void StopServer(bool save = true, string reason = "Server shutting down!") - { - ForceKickAll(reason); - if (save) - SaveManager.Instance.SaveWorld(); - - // Save takes a while so kick again - ForceKickAll(reason); - - // Broadcast so console can see we are shutting down as well - TShock.Utils.Broadcast(reason, Color.Red); - - // Disconnect after kick as that signifies server is exiting and could cause a race - Netplay.disconnect = true; - } - - /// - /// Kicks a player from the server without checking for immunetokick permission. - /// - /// int player - /// string reason - /// bool silent (default: false) - public void ForceKick(TSPlayer player, string reason, bool silent = false) - { - Kick(player, reason, true, silent); - } - - /// - /// Kicks a player from the server. - /// - /// int player - /// string reason - /// bool force (default: false) - /// bool silent (default: false) - /// bool silent (default: null) - public bool Kick(TSPlayer player, string reason, bool force = false, bool silent = false, string adminUserName = null) - { - if (!player.ConnectionAlive) - return true; - if (force || !player.Group.HasPermission(Permissions.immunetokick)) - { - string playerName = player.Name; - player.SilentKickInProgress = silent; - player.Disconnect(string.Format("Kicked: {0}", reason)); - Log.ConsoleInfo(string.Format("Kicked {0} for : {1}", playerName, reason)); - string verb = force ? "force " : ""; - if (string.IsNullOrWhiteSpace(adminUserName)) - Broadcast(string.Format("{0} was {1}kicked for {2}", playerName, verb, reason.ToLower())); - else - Broadcast(string.Format("{0} {1}kicked {2} for {3}", adminUserName, verb, playerName, reason.ToLower())); - return true; - } - return false; - } - - /// - /// Bans and kicks a player from the server. - /// - /// int player - /// string reason - /// bool force (default: false) - /// bool silent (default: null) - public bool Ban(TSPlayer player, string reason, bool force = false, string adminUserName = null) - { - if (!player.ConnectionAlive) - return true; - if (force || !player.Group.HasPermission(Permissions.immunetoban)) - { - string ip = player.IP; - string playerName = player.Name; - TShock.Bans.AddBan(ip, playerName, reason); - player.Disconnect(string.Format("Banned: {0}", reason)); - Log.ConsoleInfo(string.Format("Banned {0} for : {1}", playerName, reason)); - string verb = force ? "force " : ""; - if (string.IsNullOrWhiteSpace(adminUserName)) - Broadcast(string.Format("{0} was {1}banned for {1}", playerName, verb, reason.ToLower())); - else - Broadcast(string.Format("{0} {1}banned {1} for {2}", adminUserName, verb, playerName, reason.ToLower())); - return true; - } - return false; - } - - /// - /// Shows a file to the user. - /// - /// int player - /// string filename reletave to savedir - //Todo: Fix this - public void ShowFileToUser(TSPlayer player, string file) - { - string foo = ""; - using (var tr = new StreamReader(Path.Combine(TShock.SavePath, file))) - { - while ((foo = tr.ReadLine()) != null) - { - foo = foo.Replace("%map%", Main.worldName); - foo = foo.Replace("%players%", GetPlayers()); - //foo = SanitizeString(foo); - if (foo.Substring(0, 1) == "%" && foo.Substring(12, 1) == "%") //Look for a beginning color code. - { - string possibleColor = foo.Substring(0, 13); - foo = foo.Remove(0, 13); - float[] pC = {0, 0, 0}; - possibleColor = possibleColor.Replace("%", ""); - string[] pCc = possibleColor.Split(','); - if (pCc.Length == 3) - { - try - { - player.SendMessage(foo, (byte) Convert.ToInt32(pCc[0]), (byte) Convert.ToInt32(pCc[1]), - (byte) Convert.ToInt32(pCc[2])); - continue; - } - catch (Exception e) - { - Log.Error(e.ToString()); - } - } - } - player.SendMessage(foo); - } - } - } - - /// - /// Returns a Group from the name of the group - /// - /// string groupName - public Group GetGroup(string groupName) - { - //first attempt on cached groups - for (int i = 0; i < TShock.Groups.groups.Count; i++) - { - if (TShock.Groups.groups[i].Name.Equals(groupName)) - { - return TShock.Groups.groups[i]; - } - } - return new Group(TShock.Config.DefaultGuestGroupName); - } - - /// - /// Returns an IPv4 address from a DNS query - /// - /// string ip - public string GetIPv4Address(string hostname) - { - try - { - //Get the ipv4 address from GetHostAddresses, if an ip is passed it will return that ip - var ip = Dns.GetHostAddresses(hostname).FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork); - //if the dns query was successful then return it, otherwise return an empty string - return ip != null ? ip.ToString() : ""; - } - catch (SocketException) - { - } - return ""; - } - - public string HashAlgo = "sha512"; - - public readonly Dictionary> HashTypes = new Dictionary> - { - {"sha512", () => new SHA512Managed()}, - {"sha256", () => new SHA256Managed()}, - {"md5", () => new MD5Cng()}, - {"sha512-xp", () => SHA512.Create()}, - {"sha256-xp", () => SHA256.Create()}, - {"md5-xp", () => MD5.Create()}, - }; - - /// - /// Returns a Sha256 string for a given string - /// - /// bytes to hash - /// string sha256 - public string HashPassword(byte[] bytes) - { - if (bytes == null) - throw new NullReferenceException("bytes"); - Func func; - if (!HashTypes.TryGetValue(HashAlgo.ToLower(), out func)) - throw new NotSupportedException("Hashing algorithm {0} is not supported".SFormat(HashAlgo.ToLower())); - - using (var hash = func()) - { - var ret = hash.ComputeHash(bytes); - return ret.Aggregate("", (s, b) => s + b.ToString("X2")); - } - } - - /// - /// Returns a Sha256 string for a given string - /// - /// bytes to hash - /// string sha256 - public string HashPassword(string password) - { - if (string.IsNullOrEmpty(password) || password == "non-existant password") - return "non-existant password"; - return HashPassword(Encoding.UTF8.GetBytes(password)); - } - - /// - /// Checks if the string contains any unprintable characters - /// - /// String to check - /// True if the string only contains printable characters - public bool ValidString(string str) - { - foreach (var c in str) - { - if (c < 0x20 || c > 0xA9) - return false; - } - return true; - } - - /// - /// Checks if world has hit the max number of chests - /// - /// True if the entire chest array is used - public bool MaxChests() - { - for (int i = 0; i < Main.chest.Length; i++) - { - if (Main.chest[i] == null) - return false; - } - return true; - } - - /// - /// Searches for a projectile by identity and owner - /// - /// identity - /// owner - /// projectile ID - public int SearchProjectile(short identity, int owner) - { - for (int i = 0; i < Main.maxProjectiles; i++) - { - if (Main.projectile[i].identity == identity && Main.projectile[i].owner == owner) - return i; - } - return 1000; - } - - /// - /// Sanitizes input strings - /// - /// string - /// sanitized string - public string SanitizeString(string str) - { - var returnstr = str.ToCharArray(); - for (int i = 0; i < str.Length; i++) - { - if (!ValidString(str[i].ToString())) - returnstr[i] = ' '; - } - return new string(returnstr); - } - } +/* +TShock, a server mod for Terraria +Copyright (C) 2011 The TShock Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using Terraria; + +namespace TShockAPI +{ + public class Utils + { + private readonly static int firstItemPrefix = 1; + private readonly static int lastItemPrefix = 83; + // Utils is a Singleton + private static readonly Utils instance = new Utils(); + private Utils() {} + public static Utils Instance { get { return instance; } } + + public Random Random = new Random(); + //private static List groups = new List(); + + /// + /// Provides the real IP address from a RemoteEndPoint string that contains a port and an IP + /// + /// A string IPv4 address in IP:PORT form. + /// A string IPv4 address. + public string GetRealIP(string mess) + { + return mess.Split(':')[0]; + } + + /// + /// Used for some places where a list of players might be used. + /// + /// String of players seperated by commas. + public string GetPlayers() + { + var sb = new StringBuilder(); + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active) + { + if (sb.Length != 0) + { + sb.Append(", "); + } + sb.Append(player.Name); + } + } + return sb.ToString(); + } + + /// + /// Used for some places where a list of players might be used. + /// + /// String of players and their id seperated by commas. + public string GetPlayersWithIds() + { + var sb = new StringBuilder(); + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active) + { + if (sb.Length != 0) + { + sb.Append(", "); + } + sb.Append(player.Name); + string id = "( " + Convert.ToString(TShock.Users.GetUserID(player.UserAccountName)) + " )"; + sb.Append(id); + } + } + return sb.ToString(); + } + + /// + /// Finds a player and gets IP as string + /// + /// Player name + public string GetPlayerIP(string playername) + { + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active) + { + if (playername.ToLower() == player.Name.ToLower()) + { + return player.IP; + } + } + } + return null; + } + + /// + /// It's a clamp function + /// + /// + /// Value to clamp + /// Maximum bounds of the clamp + /// Minimum bounds of the clamp + /// + public T Clamp(T value, T max, T min) + where T : IComparable + { + T result = value; + if (value.CompareTo(max) > 0) + result = max; + if (value.CompareTo(min) < 0) + result = min; + return result; + } + + /// + /// Saves the map data + /// + public void SaveWorld() + { + SaveManager.Instance.SaveWorld(); + } + + /// + /// Broadcasts a message to all players + /// + /// string message + public void Broadcast(string msg) + { + Broadcast(msg, Color.Green); + } + + public void Broadcast(string msg, byte red, byte green, byte blue) + { + TSPlayer.All.SendMessage(msg, red, green, blue); + TSPlayer.Server.SendMessage(msg, red, green, blue); + Log.Info(string.Format("Broadcast: {0}", msg)); + } + + public void Broadcast(string msg, Color color) + { + Broadcast(msg, color.R, color.G, color.B); + } + + /// + /// Sends message to all users with 'logs' permission. + /// + /// Message to send + /// Color of the message + public void SendLogs(string log, Color color) + { + Log.Info(log); + TSPlayer.Server.SendMessage(log, color); + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active && player.Group.HasPermission(Permissions.logs) && player.DisplayLogs && + TShock.Config.DisableSpewLogs == false) + player.SendMessage(log, color); + } + } + + /// + /// The number of active players on the server. + /// + /// int playerCount + public int ActivePlayers() + { + return Main.player.Where(p => null != p && p.active).Count(); + } + + /// + /// Finds a player ID based on name + /// + /// Player name + /// + public List FindPlayer(string ply) + { + var found = new List(); + // Avoid errors caused by null search + if (null == ply) + return found; + ply = ply.ToLower(); + foreach (TSPlayer player in TShock.Players) + { + if (player == null) + continue; + + string name = player.Name.ToLower(); + if (name.Equals(ply)) + return new List {player}; + if (name.Contains(ply)) + found.Add(player); + } + return found; + } + + /// + /// Gets a random clear tile in range + /// + /// Bound X + /// Bound Y + /// Range on the X axis + /// Range on the Y axis + /// X location + /// Y location + public void GetRandomClearTileWithInRange(int startTileX, int startTileY, int tileXRange, int tileYRange, + out int tileX, out int tileY) + { + int j = 0; + do + { + if (j == 100) + { + tileX = startTileX; + tileY = startTileY; + break; + } + + tileX = startTileX + Random.Next(tileXRange*-1, tileXRange); + tileY = startTileY + Random.Next(tileYRange*-1, tileYRange); + j++; + } while (TileValid(tileX, tileY) && !TileClear(tileX, tileY)); + } + + /// + /// Determines if a tile is valid + /// + /// Location X + /// Location Y + /// If the tile is valid + private bool TileValid(int tileX, int tileY) + { + return tileX >= 0 && tileX <= Main.maxTilesX && tileY >= 0 && tileY <= Main.maxTilesY; + } + + /// + /// Clears a tile + /// + /// Location X + /// Location Y + /// The state of the tile + private bool TileClear(int tileX, int tileY) + { + return !Main.tile[tileX, tileY].active; + } + + /// + /// Gets a list of items by ID or name + /// + /// Item ID or name + /// List of Items + public List GetItemByIdOrName(string idOrName) + { + int type = -1; + if (int.TryParse(idOrName, out type)) + { + return new List {GetItemById(type)}; + } + return GetItemByName(idOrName); + } + + /// + /// Gets an item by ID + /// + /// ID + /// Item + public Item GetItemById(int id) + { + Item item = new Item(); + item.netDefaults(id); + return item; + } + + /// + /// Gets items by name + /// + /// name + /// List of Items + public List GetItemByName(string name) + { + //Method #1 - must be exact match, allows support for different pickaxes/hammers/swords etc + for (int i = 1; i < Main.maxItemTypes; i++) + { + Item item = new Item(); + item.SetDefaults(name); + if (item.name == name) + return new List {item}; + } + //Method #2 - allows impartial matching + var found = new List(); + for (int i = -24; i < Main.maxItemTypes; i++) + { + try + { + Item item = new Item(); + item.netDefaults(i); + if (item.name.ToLower() == name.ToLower()) + return new List {item}; + if (item.name.ToLower().StartsWith(name.ToLower())) + found.Add(item); + } + catch + { + } + } + return found; + } + + /// + /// Gets an NPC by ID or Name + /// + /// + /// List of NPCs + public List GetNPCByIdOrName(string idOrName) + { + int type = -1; + if (int.TryParse(idOrName, out type)) + { + return new List {GetNPCById(type)}; + } + return GetNPCByName(idOrName); + } + + /// + /// Gets an NPC by ID + /// + /// ID + /// NPC + public NPC GetNPCById(int id) + { + NPC npc = new NPC(); + npc.netDefaults(id); + return npc; + } + + /// + /// Gets a NPC by name + /// + /// Name + /// List of matching NPCs + public List GetNPCByName(string name) + { + //Method #1 - must be exact match, allows support for different coloured slimes + for (int i = -17; i < Main.maxNPCTypes; i++) + { + NPC npc = new NPC(); + npc.SetDefaults(name); + if (npc.name == name) + return new List {npc}; + } + //Method #2 - allows impartial matching + var found = new List(); + for (int i = 1; i < Main.maxNPCTypes; i++) + { + NPC npc = new NPC(); + npc.netDefaults(i); + if (npc.name.ToLower() == name.ToLower()) + return new List {npc}; + if (npc.name.ToLower().StartsWith(name.ToLower())) + found.Add(npc); + } + return found; + } + + /// + /// Gets a buff name by id + /// + /// ID + /// name + public string GetBuffName(int id) + { + return (id > 0 && id < Main.maxBuffs) ? Main.buffName[id] : "null"; + } + + /// + /// Gets the description of a buff + /// + /// ID + /// description + public string GetBuffDescription(int id) + { + return (id > 0 && id < Main.maxBuffs) ? Main.buffTip[id] : "null"; + } + + /// + /// Gets a list of buffs by name + /// + /// name + /// Matching list of buff ids + public List GetBuffByName(string name) + { + for (int i = 1; i < Main.maxBuffs; i++) + { + if (Main.buffName[i].ToLower() == name) + return new List {i}; + } + var found = new List(); + for (int i = 1; i < Main.maxBuffs; i++) + { + if (Main.buffName[i].ToLower().StartsWith(name.ToLower())) + found.Add(i); + } + return found; + } + + /// + /// Gets a prefix based on its id + /// + /// ID + /// Prefix name + public string GetPrefixById(int id) + { + var item = new Item(); + item.SetDefaults(0); + item.prefix = (byte) id; + item.AffixName(); + return item.name.Trim(); + } + + /// + /// Gets a list of prefixes by name + /// + /// Name + /// List of prefix IDs + public List GetPrefixByName(string name) + { + Item item = new Item(); + item.SetDefaults(0); + string lowerName = name.ToLower(); + var found = new List(); + for (int i = firstItemPrefix; i <= lastItemPrefix; i++) + { + try + { + item.prefix = (byte)i; + string trimmed = item.AffixName().Trim(); + if (trimmed == name) + { + // Exact match + found.Add(i); + return found; + } + else + { + string trimmedLower = trimmed.ToLower(); + if (trimmedLower == lowerName) + { + // Exact match (caseinsensitive) + found.Add(i); + return found; + } + else if (trimmedLower.StartsWith(lowerName)) // Partial match + found.Add(i); + } + } + catch + { + } + } + return found; + } + + /// + /// Gets a prefix by ID or name + /// + /// ID or name + /// List of prefix IDs + public List GetPrefixByIdOrName(string idOrName) + { + int type = -1; + if (int.TryParse(idOrName, out type) && type >= firstItemPrefix && type <= lastItemPrefix) + { + return new List {type}; + } + return GetPrefixByName(idOrName); + } + + /// + /// Kicks all player from the server without checking for immunetokick permission. + /// + /// int player + /// string reason + public void ForceKickAll(string reason) + { + foreach (TSPlayer player in TShock.Players) + { + if (player != null && player.Active) + { + ForceKick(player, reason); + } + } + } + + /// + /// Stops the server after kicking all players with a reason message, and optionally saving the world + /// + /// bool perform a world save before stop (default: true) + /// string reason (default: "Server shutting down!") + public void StopServer(bool save = true, string reason = "Server shutting down!") + { + ForceKickAll(reason); + if (save) + SaveManager.Instance.SaveWorld(); + + // Save takes a while so kick again + ForceKickAll(reason); + + // Broadcast so console can see we are shutting down as well + TShock.Utils.Broadcast(reason, Color.Red); + + // Disconnect after kick as that signifies server is exiting and could cause a race + Netplay.disconnect = true; + } + + /// + /// Kicks a player from the server without checking for immunetokick permission. + /// + /// int player + /// string reason + /// bool silent (default: false) + public void ForceKick(TSPlayer player, string reason, bool silent = false) + { + Kick(player, reason, true, silent); + } + + /// + /// Kicks a player from the server. + /// + /// int player + /// string reason + /// bool force (default: false) + /// bool silent (default: false) + /// bool silent (default: null) + public bool Kick(TSPlayer player, string reason, bool force = false, bool silent = false, string adminUserName = null) + { + if (!player.ConnectionAlive) + return true; + if (force || !player.Group.HasPermission(Permissions.immunetokick)) + { + string playerName = player.Name; + player.SilentKickInProgress = silent; + player.Disconnect(string.Format("Kicked: {0}", reason)); + Log.ConsoleInfo(string.Format("Kicked {0} for : {1}", playerName, reason)); + string verb = force ? "force " : ""; + if (string.IsNullOrWhiteSpace(adminUserName)) + Broadcast(string.Format("{0} was {1}kicked for {2}", playerName, verb, reason.ToLower())); + else + Broadcast(string.Format("{0} {1}kicked {2} for {3}", adminUserName, verb, playerName, reason.ToLower())); + return true; + } + return false; + } + + /// + /// Bans and kicks a player from the server. + /// + /// int player + /// string reason + /// bool force (default: false) + /// bool silent (default: null) + public bool Ban(TSPlayer player, string reason, bool force = false, string adminUserName = null) + { + if (!player.ConnectionAlive) + return true; + if (force || !player.Group.HasPermission(Permissions.immunetoban)) + { + string ip = player.IP; + string playerName = player.Name; + TShock.Bans.AddBan(ip, playerName, reason); + player.Disconnect(string.Format("Banned: {0}", reason)); + Log.ConsoleInfo(string.Format("Banned {0} for : {1}", playerName, reason)); + string verb = force ? "force " : ""; + if (string.IsNullOrWhiteSpace(adminUserName)) + Broadcast(string.Format("{0} was {1}banned for {1}", playerName, verb, reason.ToLower())); + else + Broadcast(string.Format("{0} {1}banned {1} for {2}", adminUserName, verb, playerName, reason.ToLower())); + return true; + } + return false; + } + + /// + /// Shows a file to the user. + /// + /// int player + /// string filename reletave to savedir + //Todo: Fix this + public void ShowFileToUser(TSPlayer player, string file) + { + string foo = ""; + using (var tr = new StreamReader(Path.Combine(TShock.SavePath, file))) + { + while ((foo = tr.ReadLine()) != null) + { + foo = foo.Replace("%map%", Main.worldName); + foo = foo.Replace("%players%", GetPlayers()); + //foo = SanitizeString(foo); + if (foo.Substring(0, 1) == "%" && foo.Substring(12, 1) == "%") //Look for a beginning color code. + { + string possibleColor = foo.Substring(0, 13); + foo = foo.Remove(0, 13); + float[] pC = {0, 0, 0}; + possibleColor = possibleColor.Replace("%", ""); + string[] pCc = possibleColor.Split(','); + if (pCc.Length == 3) + { + try + { + player.SendMessage(foo, (byte) Convert.ToInt32(pCc[0]), (byte) Convert.ToInt32(pCc[1]), + (byte) Convert.ToInt32(pCc[2])); + continue; + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + } + player.SendMessage(foo); + } + } + } + + /// + /// Returns a Group from the name of the group + /// + /// string groupName + public Group GetGroup(string groupName) + { + //first attempt on cached groups + for (int i = 0; i < TShock.Groups.groups.Count; i++) + { + if (TShock.Groups.groups[i].Name.Equals(groupName)) + { + return TShock.Groups.groups[i]; + } + } + return new Group(TShock.Config.DefaultGuestGroupName); + } + + /// + /// Returns an IPv4 address from a DNS query + /// + /// string ip + public string GetIPv4Address(string hostname) + { + try + { + //Get the ipv4 address from GetHostAddresses, if an ip is passed it will return that ip + var ip = Dns.GetHostAddresses(hostname).FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork); + //if the dns query was successful then return it, otherwise return an empty string + return ip != null ? ip.ToString() : ""; + } + catch (SocketException) + { + } + return ""; + } + + public string HashAlgo = "sha512"; + + public readonly Dictionary> HashTypes = new Dictionary> + { + {"sha512", () => new SHA512Managed()}, + {"sha256", () => new SHA256Managed()}, + {"md5", () => new MD5Cng()}, + {"sha512-xp", () => SHA512.Create()}, + {"sha256-xp", () => SHA256.Create()}, + {"md5-xp", () => MD5.Create()}, + }; + + /// + /// Returns a Sha256 string for a given string + /// + /// bytes to hash + /// string sha256 + public string HashPassword(byte[] bytes) + { + if (bytes == null) + throw new NullReferenceException("bytes"); + Func func; + if (!HashTypes.TryGetValue(HashAlgo.ToLower(), out func)) + throw new NotSupportedException("Hashing algorithm {0} is not supported".SFormat(HashAlgo.ToLower())); + + using (var hash = func()) + { + var ret = hash.ComputeHash(bytes); + return ret.Aggregate("", (s, b) => s + b.ToString("X2")); + } + } + + /// + /// Returns a Sha256 string for a given string + /// + /// bytes to hash + /// string sha256 + public string HashPassword(string password) + { + if (string.IsNullOrEmpty(password) || password == "non-existant password") + return "non-existant password"; + return HashPassword(Encoding.UTF8.GetBytes(password)); + } + + /// + /// Checks if the string contains any unprintable characters + /// + /// String to check + /// True if the string only contains printable characters + public bool ValidString(string str) + { + foreach (var c in str) + { + if (c < 0x20 || c > 0xA9) + return false; + } + return true; + } + + /// + /// Checks if world has hit the max number of chests + /// + /// True if the entire chest array is used + public bool MaxChests() + { + for (int i = 0; i < Main.chest.Length; i++) + { + if (Main.chest[i] == null) + return false; + } + return true; + } + + /// + /// Searches for a projectile by identity and owner + /// + /// identity + /// owner + /// projectile ID + public int SearchProjectile(short identity, int owner) + { + for (int i = 0; i < Main.maxProjectiles; i++) + { + if (Main.projectile[i].identity == identity && Main.projectile[i].owner == owner) + return i; + } + return 1000; + } + + /// + /// Sanitizes input strings + /// + /// string + /// sanitized string + public string SanitizeString(string str) + { + var returnstr = str.ToCharArray(); + for (int i = 0; i < str.Length; i++) + { + if (!ValidString(str[i].ToString())) + returnstr[i] = ' '; + } + return new string(returnstr); + } + } } \ No newline at end of file diff --git a/TShockRestTestPlugin/Properties/AssemblyInfo.cs b/TShockRestTestPlugin/Properties/AssemblyInfo.cs index 17cb9a46a..f9320bbe3 100644 --- a/TShockRestTestPlugin/Properties/AssemblyInfo.cs +++ b/TShockRestTestPlugin/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ClassLibrary1")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Multiplay")] -[assembly: AssemblyProduct("ClassLibrary1")] -[assembly: AssemblyCopyright("Copyright © Multiplay 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c6aed7ee-6282-49a2-8177-b79cad20d6d3")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClassLibrary1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Multiplay")] +[assembly: AssemblyProduct("ClassLibrary1")] +[assembly: AssemblyCopyright("Copyright © Multiplay 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c6aed7ee-6282-49a2-8177-b79cad20d6d3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TShockRestTestPlugin/TShockRestTestPlugin.cs b/TShockRestTestPlugin/TShockRestTestPlugin.cs index 403b6f8fc..385ba4fc2 100644 --- a/TShockRestTestPlugin/TShockRestTestPlugin.cs +++ b/TShockRestTestPlugin/TShockRestTestPlugin.cs @@ -1,192 +1,192 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; -using System.Web; -using System.Web.Script.Serialization; -using System.Text.RegularExpressions; -using Microsoft.VisualStudio.TestTools.WebTesting; -using Microsoft.VisualStudio.TestTools.WebTesting.Rules; -using Rests; - -namespace TshockRestTestPlugin -{ - [DisplayName("JSON Status")] - [Description("Checks to see the that the JSON response has the specified status response")] - public class JsonValidateStatus : JsonValidate - { - public override void Validate(object sender, ValidationEventArgs e) - { - if (null != ValidateJson(sender, e)) - e.IsValid = true; - } - } - - [DisplayName("JSON Regexp Property")] - [Description("Checks to see the that the JSON response contains the specified property and is matches the specified regexp")] - public class JsonValidateRegexpProperty : JsonValidateProperty - { - // The name of the desired JSON property - [DisplayName("Regexp")] - [DefaultValue(true)] - public new bool UseRegularExpression { get { return base.UseRegularExpression; } set { base.UseRegularExpression = value; } } - } - - [DisplayName("JSON Error")] - [Description("Checks to see the that the JSON response contains the specified error")] - public class JsonValidateError : JsonValidateProperty - { - // The status of the JSON request - [DisplayName("JSON Status")] - [DefaultValue("400")] - public new string JSonStatus { get { return base.JSonStatus; } set { base.JSonStatus = value; } } - - // The name of the desired JSON property - [DisplayName("Property")] - [DefaultValue("error")] - public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } - } - - [DisplayName("JSON Missing Parameter")] - [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] - public class JsonValidateMissingParameter : JsonValidateError - { - // The value of the desired JSON property - [DisplayName("Missing Value")] - public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or empty {0} parameter", value); } } - } - - [DisplayName("JSON Invalid Parameter")] - [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] - public class JsonValidateInvalidParameter : JsonValidateError - { - // The value of the desired JSON property - [DisplayName("Invalid Value")] - public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or invalid {0} parameter", value); } } - } - - [DisplayName("JSON Response")] - [Description("Checks to see the that the JSON response contains the specified message")] - public class JsonValidateResponse : JsonValidateProperty - { - // The name of the desired JSON property - [DisplayName("Response")] - [DefaultValue("response")] - public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } - } - - [DisplayName("JSON Property")] - [Description("Checks to see the that the JSON response contains the specified property and is set to the specified value")] - public class JsonValidateProperty : JsonValidate - { - // The name of the desired JSON property - [DisplayName("Property")] - public string PropertyName { get; set; } - - // The value of the desired JSON property - [DisplayName("Value")] - public string PropertyValue { get; set; } - - // Is the value a regexp of the desired JSON property - [DisplayName("Regexp")] - [DefaultValue(false)] - public bool UseRegularExpression { get; set; } - - public override void Validate(object sender, ValidationEventArgs e) - { - RestObject response = ValidateJson(sender, e); - if (null == response) - return; - - if (null == response[PropertyName]) - { - e.Message = String.Format("{0} Not Found", PropertyName); - e.IsValid = false; - return; - } - - if (UseRegularExpression) - { - var re = new Regex(PropertyValue); - if (!re.IsMatch((string)response[PropertyName])) - { - e.Message = String.Format("{0} => '{1}' !~ '{2}'", PropertyName, response[PropertyName], PropertyValue); - e.IsValid = false; - return; - } - } - else - { - if (PropertyValue != (string)response[PropertyName]) - { - e.Message = String.Format("{0} => '{1}' != '{2}'", PropertyName, response[PropertyName], PropertyValue); - e.IsValid = false; - return; - } - } - - e.IsValid = true; - //e.WebTest.Context.Add(ContextParameterName, propertyValue); - } - } - - [DisplayName("JSON Has Properties")] - [Description("Checks to see the that the JSON response contains the specified properties (comma seperated)")] - public class JsonHasProperties : JsonValidate - { - // The name of the desired JSON properties to check - [DisplayName("Properties")] - [Description("A comma seperated list of property names to check exist")] - public string PropertyNames { get; set; } - - //--------------------------------------------------------------------- - public override void Validate(object sender, ValidationEventArgs e) - { - RestObject response = ValidateJson(sender, e); - if (null == response) - return; - foreach (var p in PropertyNames.Split(',')) - { - if (null == response[p]) - { - e.Message = String.Format("'{0}' Not Found", p); - e.IsValid = false; - return; - } - } - e.IsValid = true; - - //e.WebTest.Context.Add(ContextParameterName, propertyValue); - } - } - - public abstract class JsonValidate : ValidationRule - { - // The status of the JSON request - [DisplayName("JSON Status")] - [DefaultValue("200")] - public string JSonStatus { get; set; } - - public RestObject ValidateJson(object sender, ValidationEventArgs e) - { - if (string.IsNullOrWhiteSpace(e.Response.BodyString)) - { - e.IsValid = false; - e.Message = String.Format("Empty or null response {0}", e.Response.StatusCode); - return null; - } - JavaScriptSerializer serialiser = new JavaScriptSerializer(); - //dynamic data = serialiser.Deserialize(e.Response.BodyString); - RestObject response = serialiser.Deserialize(e.Response.BodyString); - - if (JSonStatus != response.Status) - { - e.IsValid = false; - e.Message = String.Format("Response Status '{0}' not '{1}'", response.Status, JSonStatus); - return null; - } - - return response; - } - } +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Web; +using System.Web.Script.Serialization; +using System.Text.RegularExpressions; +using Microsoft.VisualStudio.TestTools.WebTesting; +using Microsoft.VisualStudio.TestTools.WebTesting.Rules; +using Rests; + +namespace TshockRestTestPlugin +{ + [DisplayName("JSON Status")] + [Description("Checks to see the that the JSON response has the specified status response")] + public class JsonValidateStatus : JsonValidate + { + public override void Validate(object sender, ValidationEventArgs e) + { + if (null != ValidateJson(sender, e)) + e.IsValid = true; + } + } + + [DisplayName("JSON Regexp Property")] + [Description("Checks to see the that the JSON response contains the specified property and is matches the specified regexp")] + public class JsonValidateRegexpProperty : JsonValidateProperty + { + // The name of the desired JSON property + [DisplayName("Regexp")] + [DefaultValue(true)] + public new bool UseRegularExpression { get { return base.UseRegularExpression; } set { base.UseRegularExpression = value; } } + } + + [DisplayName("JSON Error")] + [Description("Checks to see the that the JSON response contains the specified error")] + public class JsonValidateError : JsonValidateProperty + { + // The status of the JSON request + [DisplayName("JSON Status")] + [DefaultValue("400")] + public new string JSonStatus { get { return base.JSonStatus; } set { base.JSonStatus = value; } } + + // The name of the desired JSON property + [DisplayName("Property")] + [DefaultValue("error")] + public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } + } + + [DisplayName("JSON Missing Parameter")] + [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] + public class JsonValidateMissingParameter : JsonValidateError + { + // The value of the desired JSON property + [DisplayName("Missing Value")] + public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or empty {0} parameter", value); } } + } + + [DisplayName("JSON Invalid Parameter")] + [Description("Checks to see the that the JSON response indicates a missing or invalid parameter")] + public class JsonValidateInvalidParameter : JsonValidateError + { + // The value of the desired JSON property + [DisplayName("Invalid Value")] + public new string PropertyValue { get { return base.PropertyValue; } set { base.PropertyValue = String.Format("Missing or invalid {0} parameter", value); } } + } + + [DisplayName("JSON Response")] + [Description("Checks to see the that the JSON response contains the specified message")] + public class JsonValidateResponse : JsonValidateProperty + { + // The name of the desired JSON property + [DisplayName("Response")] + [DefaultValue("response")] + public new string PropertyName { get { return base.PropertyName; } set { base.PropertyName = value; } } + } + + [DisplayName("JSON Property")] + [Description("Checks to see the that the JSON response contains the specified property and is set to the specified value")] + public class JsonValidateProperty : JsonValidate + { + // The name of the desired JSON property + [DisplayName("Property")] + public string PropertyName { get; set; } + + // The value of the desired JSON property + [DisplayName("Value")] + public string PropertyValue { get; set; } + + // Is the value a regexp of the desired JSON property + [DisplayName("Regexp")] + [DefaultValue(false)] + public bool UseRegularExpression { get; set; } + + public override void Validate(object sender, ValidationEventArgs e) + { + RestObject response = ValidateJson(sender, e); + if (null == response) + return; + + if (null == response[PropertyName]) + { + e.Message = String.Format("{0} Not Found", PropertyName); + e.IsValid = false; + return; + } + + if (UseRegularExpression) + { + var re = new Regex(PropertyValue); + if (!re.IsMatch((string)response[PropertyName])) + { + e.Message = String.Format("{0} => '{1}' !~ '{2}'", PropertyName, response[PropertyName], PropertyValue); + e.IsValid = false; + return; + } + } + else + { + if (PropertyValue != (string)response[PropertyName]) + { + e.Message = String.Format("{0} => '{1}' != '{2}'", PropertyName, response[PropertyName], PropertyValue); + e.IsValid = false; + return; + } + } + + e.IsValid = true; + //e.WebTest.Context.Add(ContextParameterName, propertyValue); + } + } + + [DisplayName("JSON Has Properties")] + [Description("Checks to see the that the JSON response contains the specified properties (comma seperated)")] + public class JsonHasProperties : JsonValidate + { + // The name of the desired JSON properties to check + [DisplayName("Properties")] + [Description("A comma seperated list of property names to check exist")] + public string PropertyNames { get; set; } + + //--------------------------------------------------------------------- + public override void Validate(object sender, ValidationEventArgs e) + { + RestObject response = ValidateJson(sender, e); + if (null == response) + return; + foreach (var p in PropertyNames.Split(',')) + { + if (null == response[p]) + { + e.Message = String.Format("'{0}' Not Found", p); + e.IsValid = false; + return; + } + } + e.IsValid = true; + + //e.WebTest.Context.Add(ContextParameterName, propertyValue); + } + } + + public abstract class JsonValidate : ValidationRule + { + // The status of the JSON request + [DisplayName("JSON Status")] + [DefaultValue("200")] + public string JSonStatus { get; set; } + + public RestObject ValidateJson(object sender, ValidationEventArgs e) + { + if (string.IsNullOrWhiteSpace(e.Response.BodyString)) + { + e.IsValid = false; + e.Message = String.Format("Empty or null response {0}", e.Response.StatusCode); + return null; + } + JavaScriptSerializer serialiser = new JavaScriptSerializer(); + //dynamic data = serialiser.Deserialize(e.Response.BodyString); + RestObject response = serialiser.Deserialize(e.Response.BodyString); + + if (JSonStatus != response.Status) + { + e.IsValid = false; + e.Message = String.Format("Response Status '{0}' not '{1}'", response.Status, JSonStatus); + return null; + } + + return response; + } + } } \ No newline at end of file diff --git a/TShockRestTestPlugin/TShockRestTestPlugin.csproj b/TShockRestTestPlugin/TShockRestTestPlugin.csproj index bf2dd9978..e315c7d36 100644 --- a/TShockRestTestPlugin/TShockRestTestPlugin.csproj +++ b/TShockRestTestPlugin/TShockRestTestPlugin.csproj @@ -1,62 +1,62 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {F2FEDAFB-58DE-4611-9168-A86112C346C7} - Library - Properties - TshockRestTestPlugin - TshockRestTestPlugin - v4.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - {49606449-072B-4CF5-8088-AA49DA586694} - TShockAPI - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {F2FEDAFB-58DE-4611-9168-A86112C346C7} + Library + Properties + TshockRestTestPlugin + TshockRestTestPlugin + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + {49606449-072B-4CF5-8088-AA49DA586694} + TShockAPI + + + + \ No newline at end of file diff --git a/UnitTests/RestApiTests.webtest b/UnitTests/RestApiTests.webtest index 84057748e..29e279813 100644 --- a/UnitTests/RestApiTests.webtest +++ b/UnitTests/RestApiTests.webtest @@ -1,1542 +1,1542 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file